Can't Integrate HTML's DOM in NodeJS/ExpressJS - mysql

Good day, hoomans! I badly need your help!
My question: Is there any way (in NodeJS/ExpressJS) to dynamically alter an element such as adding new li upon POST request like after clicking the submit button (without using jsdom though)?
I am developing a very simple application which should allow a client (student) to keep track of the lessons in his/her every class, monitor his/her grades, etc., with simple dynamic and real-time features. I am using Node.js EXPRESS, mySQL and AngularJS for this.
I created a feature where a student can search for a class then receive a list of results real-time, which basically means I want to dynamically add li elements upon request without reloading the page or redirecting the client to another page.
The process is: (1) the student types in the name of a class, (2) pass the textfield's value upon request (post), (3) use the value as key for database search, (4) then return the data extracted from the database by populating the ul element.
The database thing works. It is able to retrieve data from the database using the value entered in the textfield. However, when I add the code to dynamically add li element, I receive a runtime error every time the request is made. The code for this is found inside routes/grades.js.
The error I get is:
throw err; // Rethrow non-MySQL errors
^
TypeError: req.body.getElementById is not a function
and that is caused by this code block
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode(reqObj["className"]));
I believe createElement and createTextNode will also cause the same error message.
I think this can be solved with jsdom but when I tried to install it through npm, I only received lots of errors so I gave up. Besides, I believe there is a simpler solution to this that I don't know yet.
Here are the primary files for the functionality I mentioned above.
views/grades.ejs
<!DOCTYPE html>
<html ng-app="ClassSaber">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="javascripts/app.js" type="text/javascript"></script>
</head>
<body ng-controller="classController">
<% include template/header2.ejs %>
<div class="lessons" id="homebranding_top">
<section>
<h1>Grades</h1>
<hr>
</section>
<section>
<p>
Keeping track of your progress eh? That's great! Search your class and we'll show your grade.
</p>
</section>
<form>
<section id="class_search">
<input type="text" id="search" ng-model="data.className" placeholder="Enter your class here...">
<input type="submit" value="Search" ng-click="classFun()">
<ul id="class_list">
<li ng-repeat="item in list | filter: data.className">
{{item.Class_Name}}
</li>
</ul>
</section>
</form>
</div>
</body>
</html>
routes/grades.js
var express = require('express');
var router = express.Router();
var path = require('path');
/* GET lessons page. */
router.get('/grades', function(req, res, next) {
res.render('grades', { title: 'Class Saber | Grades' });
});
module.exports = router;
//search class in the database
router.post('/grades', function(req, res, next){
try{
var reqObj = req.body;
console.log("Request Object: " + reqObj["className"]);
req.getConnection(function(err, conn){
if(err){
console.error('SQL Connection error: ', err);
return next(err);
}
else{
var insertSql = "SELECT Class_Name FROM classes WHERE Class_Name LIKE ?";
var insertValues = [
'%' + reqObj["className"] + '%'
];
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode(reqObj["className"]));
});
}
});
}
catch(ex){
console.err("Internal error: " + ex);
return next(ex);
}
});
public/javascripts/app.js
var app = angular.module('ClassSaber', []);
app.controller('classController', function($scope, $http){
$scope.data = {};
$scope.list = [
{Class_Name: 'Math 101'},
{Class_Name: 'Physics 101'},
{Class_Name: 'Major Elective: Quantum Mechanics'}
];
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
})
}
});

req.body contains the body of the request (the data you pass with your $http call) , and not the body element of the DOM. You cannot access client side elements (like DOM) from a server side environment (like nodejs) and the other way round. If you want to make changes to the DOM then return the instructions what has to be changed with your response, and to the corresponding changes in the browser.
I do not use angular so I can't tell you directly how to do it. But in general it would be something like that:
var query = conn.query(insertSql, insertValues, function(err, result) {
if (err) {
console.error('SQL error: ', err);
return next(err);
}
// response with a list of action to be applied
res.send([{
action : 'append-to-dom',
info : {
/* all informations you need for this e.g. reqObj["className"] */
}
}]);
});
In your client side code you would check for the actions you have to do:
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function(httpResponse) {
// check the content of your response if it contains actions
/*
var ul = req.body.getElementById("search");
var li = req.body.createElement("li");
li.appendChild(req.body.createTextNode( .. the data from your response ... ))
*/
})
How you would structure the response is up to you and depends on the environment.
Angular might already have a specific pattern how to do this, but as I said, I do not use angular so I can't tell you.

The concept that t.niese gave me was really helpful and I was able to fix the problem.
Here are the changes I made as per the suggested answer:
In my routes
var query = conn.query(insertSql, insertValues, function(err, result){
if(err){
console.error('SQL error: ', err);
return next(err);
}
var class_array = [];
for(var i=0; i<result.length; i++){
class_array.push(result[i]);
}
console.log(class_array.valueOf());
res.send([{
info: class_array.valueOf()
}])
});
and in my client-side code
$scope.classFun = function(){
console.log('Client triggered class search function...');
$http({
url: 'http://localhost:3000/grades',
method: 'POST',
data: $scope.data
}).then(function (httpResponse){
console.log('response', httpResponse);
var tbody = document.getElementById("class_list_data");
while(tbody.firstElementChild){
tbody.removeChild(tbody.firstChild);
}
for(var i=0; i<httpResponse.data.length; i++){
for(var j=0; j<httpResponse.data[i].info.length; j++){
var tr = document.createElement("tr");
var td = document.createElement("td");
td.appendChild(document.createTextNode(httpResponse.data[i].info[j].Class_Name.toString()));
tr.appendChild(td);
tbody.appendChild(tr);
}
}
})
}
Also, I made little changes with my template. Instead of list, I use table.
<div id="homebranding_middle">
<table id="class_list">
<thead>
<th>CLASS DESCRIPTION</th>
<th>SCHEDULE</th>
<th>CLASSROOM ASSIGNMENT</th>
<th>INSTRUCTOR</th>
</thead>
<tbody id="class_list_data">
<tr id="class_list_row" ng-repeat="item in list | filter: {Class_Name: data.className}">
<td>{{item.Class_Name}}</td>
<td>{{item.Class_Code}}</td>
<td>{{item.Class_Room}}</td>
<td>{{item.Class_Instructor}}</td>
<dynamic></dynamic>
</tr>
</tbody>
</table>
</div>
All in all, my /grades page can actually do something now. I get status code 200 and all retrieved data from the DB could be played out.
localhost:3000/grades
Going pretty well.
Many thanks to t.niese! Cheers!

Related

Node.js - can it be used for Desktop app development - MySQL, DataTable & File Open

Since last 3days, I am after this, not sure I understood its purpose properly - Node.js/Electron.
Few years back I had built a simple VB.net application - It connects to Mysql (contains a table of filename with path), shows the filenamesPath as rows in grid, upon double click, it opens the file.
Can I do such a thing in Node.js or Electron?.
1) I am able to make a js file with a button which can open a local file, in Node.js desktop app window (not browser). [https://www.codediesel.com/nodejs/how-to-open-various-desktop-applications-from-nodejs/ ].
2) Also I am able to view mySql table as html table in browser with localhost:port as well as the rows in console-log window [https://www.sitepoint.com/using-node-mysql-javascript-client/]
Is it possible to club both of these 2, Or Should I try something else. [As the rows are more than 100K, would need also Ajax]
EDITED:
test.html
<html>
<head>
<script>window.$ = window.jQuery = require('./js/jquery.js');</script>
<meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline';">
</head>
<body>
<h1>Electron MySQL Example</h1>
<div id="resultDiv"></div>
<div>
<input type="button" id="action-btn" value="Retrieve 10 first rows in the database" />
<table id="table" border="1">
<tbody>
</tbody>
</table>
</div>
<script>
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '10.251.198.2',
user : 'root',
password : '',
database : 'test'
});
connection.connect();
var sql = 'SELECT `id`,`name` FROM `employees`';
connection.query(sql, function (error, results, fields) {
if (error) console.log(error.code);
else {
console.log(results);
$('#resultDiv').text(results[0].name); //emp_name is column name in your database
}
});
connection.end();
</script>
<!---New --->
<script>
var mysql = require('mysql');
function el(selector) {
return document.getElementById(selector);
}
el('action-btn').addEventListener('click', function(){
// Get the mysql service
getFirstTenRows(function(rows){
var html = '';
rows.forEach(function(row){
html += '<tr>';
html += '<td>';
html += row.id;
html += '</td>';
html += '<td>';
html += row.name;
html += '</td>';
html += '</tr>';
console.log(row);
});
document.querySelector('#table > tbody').innerHTML = html;
});
},false);
function getFirstTenRows(callback){
var mysql = require('mysql');
// Add the credentials to access your database
var connection = mysql.createConnection({
host : '10.251.198.2',
user : 'root',
password : '',
database : 'test'
});
// connect to mysql
connection.connect(function(err) {
// in case of error
if(err){
console.log(err.code);
console.log(err.fatal);
}
});
// Perform a query
$query = 'SELECT `id`,`name` FROM `employees` LIMIT 10';
connection.query($query, function(err, rows, fields) {
if(err){
console.log("An error ocurred performing the query.");
console.log(err);
return;
}
callback(rows);
console.log("Query succesfully executed");
});
// Close the connection
connection.end(function(){
// The connection has been closed
});
}
</script>
</body>
</html>
Index.js
const electron = require('electron');
const app = electron.app;
const path = require('path');
const url = require('url');
const BrowserWindow = electron.BrowserWindow;
var mainWindow;
app.on('ready',function(){
mainWindow = new BrowserWindow({
width: 1024,
height: 768,
webPreferences: {
nodeIntegration: true
},
//backgroundColor: '#2e2c29'
});
//mainWindow.loadURL('https://github.com');
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'test.html'),
protocol: 'file:',
slashes: true
}));
});
You can use Electron to create Desktop app and connect to Mysql database. Here are couple of useful links.
https://ourcodeworld.com/articles/read/259/how-to-connect-to-a-mysql-database-in-electron-framework
https://github.com/techiediaries/electron-mysql-demo
Node JS is primarily used to create REST API, serve web pages from the server. You may create API in Node JS using Express/Restify which interacts with DB and the Electron app can consume this service. It depends on your requirement whether or not you want to have API layer.
Sure, you can build desktop Apps nowadays in Node, in fact there is multible options that you can choose from:
Electron
Meteor
NWJS
App JS
Proton Native
All of these frameworks/technology allow you to write you App in Javascript and run it on Desktop platforms.

Retrieving data from MySQL database using NodeJS and passing it to AngularJS page

I've searched and searched for a clear answer but can't seem to find it.
I'm "new" to programming, at least when it's about AngularJS and NodeJS (base languages like HTML, CSS and plain JS I'm familiar with because of school).
I want to be able to get data from a MySQL database using NodeJS and then send that data to an HTML page that has AngularJS in it.
Before I wanted to create this connection, I first used AngularJS to retrieve data directly from $scope and was able to bind it with a dropdown on html. Nice
Then, in NodeJS I made a connection to a MySQL database (here running on Workbench) and was able to retrieve data from a table and display it on console. Very nice.
But how about AngularJS request NodeJS to get data from MySQL and send it back to AngularJS? This I can't do :(
AngularJS code:
<!DOCTYPE html>
<html>
<head>
<title>HumbleMoney</title>
<!-- AngularJS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script> // AngularJS file
</head>
<body ng-app="clientesApp" ng-controller="clientesCtrl"> // Start App and Controller
<p>Selecionar um registo:</p>
<select ng-model="clienteSelecionado" ng-options="x.nome for x in clientes"></select> // dropdown that should get the "nome" value of each record in $scope.clientes
<table> // table with 2 columns that get the "nome" and "morada" values from the selected item on the above dropdown
<tr>
<td>{{clienteSelecionado.nome}}</td>
<td>{{clienteSelecionado.morada}}</td>
</tr>
</table>
<script>
var app = angular.module('clientesApp', []);
app.controller('clientesCtrl', function($scope, $http) {
$http.get('NodeJS/clientes.js') //make a GET request on the NodeJS file
.then(function(data) {
$scope.clientes = data; //make the $scope.clientes variable have the data retrieved, right?
})
});
</script>
</script>
</body>
</html>
NodeJS code:
var express = require('express');
var app = express();
app.get('/', function (req, res){ //is this how you handle GET requests to this file?
var mysql = require('mysql'); //MySQL connection info
var conexao = mysql.createConnection({
host:"localhost",
user:"root",
password:"",
database:"mydb"
});
conexao.connect(function(erro) { //MySQL connection
if (erro) {
res.send({erro})
} else {
var sql = "SELECT nome, morada FROM clientes";
conexao.query(sql, function(erro, data) {
if (erro) {
res.send({erro})
} else {
res.send({data}); //this should bind the result from the MySQL query into "res" and send it back to the requester, right?
}
});
}
});
conexao.end();
});
Here you have it. I hope someone could point me in the right direction.
Thank's a lot and happy coding! :D
So you want to learn how to use AngularJS, NodeJS and MySQL. Very nice. AngularJS and NodeJS both use JavaScript. AngularJS is 100% JavaScript. There are just few nuts and bolts that must fit together. AngularJS focuses on the frontend side, while NodeJS focuses on the backend side. MySQL is used for database management. There are just few tricks that you must use like MVC to make you code work and be robust. There are many ways you can implement your project. One of them is the following:
Start Node.js command prompt.
Create the new project directory. For example “myjspro”
cd pathto/myjspro or cd pathto\myjspro or cd pathto\myjspro
npm init
npm install mysql --save
npm install express --save
npm install body-parser --save
etc.
Once you have done the above steps, we can start coding. In your backend code you need to set up the listening port. You also need to configure the default directory. In your frontend you can use data binding to wire up your data model to your views. e.g. Scope is the glue between app controller and the view. Structure your app in a modular way. There are many building blocks we can use for our apps. The list is endless, so let's start... Double curly expressions {{ }} are used for observing, registers listeners methods and update views.
Front End:
app/view/index.html
app/js/app.js
app/js/test.js
app/lib/angular/angular.js
app/lib/jquery/jquery.js
Back End:
db/mydb2.sql
node_modules
index.js
package.json
Database:
Create the database e.g. “mydb2”
Create database user e.g. “jspro2”
Create the database user's password.
Create database tables for the project e.g. “clientes2”
To start your project you can use: node index.js or npm start with the command prompt. The app will be running at localhost. Use the browser to view the project. i.e. http://localhost:8000/
Happy coding...
index.js
//////////////////////
//
// index.js
//
///////////////////////
console.log("Start...");
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mysql = require('mysql');
var now = new Date();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname+'/app'));
var conexao = mysql.createConnection({
host: "localhost",
user: "jspro2",
password: "jspro32",
database: "mydb2"
});
conexao.connect(function(err){
if(err){
console.log(info()+" "+err);
}
else
{
console.log(info()+" connected...");
}
});
function info()
{
now = new Date();
return now.getTime();
}
app.set('port', (process.env.PORT || 8000));
app.get('/', function(req, res){
console.log(info()+" page request.... ");
res.sendFile(__dirname +'/'+'app/view/index.html');
});
app.get('/clientes', function(req, res){
console.log(info()+" clientes request.... ");
var sql = "SELECT * FROM CLIENTES2";
conexao.query(sql, function(err, result, fields){
if(err){
console.log(info()+" "+err);
res.send(info()+": dbErr...");
}
else
{
console.log(info()+" "+result);
res.send(result);
}
});
});
app.post('/clientPost', function(req, res){
var data = req.body;
var dnome = data.nome;
var dmorada = data.morada;
var sql = "INSERT INTO CLIENTES2 (nome,morada) VALUES(?, ?)";
conexao.query(sql, [dnome, dmorada], function(err, result){
if(err){
console.log(info()+":02 "+err);
res.send(info()+": dbErr02...");
}
else
{
console.log(info()+" "+ result);
res.send(result);
}
});
});
var dport = app.get('port');
app.listen(dport, function(){
console.log(info()+" "+" app is running at http://localhost:"+dport+"/");
console.log(" Hit CRTL-C to stop the node server. ");
});
//
//
app.js
/////////////////////////
//
// app.js
//
/////////////////////////////////
//alert("start...");
var now = new Date();
//Define the clientesApp module.
var clientesApp = angular.module('clientesApp', []);
//Define the clientesCtrl controller.
clientesApp.controller('clientesCtrl', function clientsList($scope, $http){
$scope.clientes = [
{
nome: 'Marc',
morada: '123 West Parade, Nome'
},
{
nome: 'Jean',
morada: '432 East Cresent, Lisboa'
}
];
$scope.feedback = now;
$scope.listView = function(){
//alert("View");
$http.get('/clientes').then(function(data){
$scope.clientes = data.data;
$scope.feedback = data;
});
};
$scope.listSubmit = function(){
//alert("Submit..");
var listData = {
nome: $scope.nome,
morada: $scope.morada
};
//alert(listData.nome);
$http.post('/clientPost', listData).then(function(data){
$scope.feedback = data;
});
};
});
//alert(now);
//
//
index.html
<!DOCTYPE html>
<!--
index.html
-->
<html lang="en">
<head>
<title>DemoJSPro</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body ng-app="clientesApp">
<h1>AngularJS Demo using NodeJS and MySQL.</h1>
<div ng-controller="clientesCtrl">
<hr>
<div>{{ feedback }}</div>
<hr>
<div>
<br>
Nome:
<input type="text" ng-model="nome">
<br>
Morada:
<input type="text" ng-model="morada">
<br>
<input type="button" value="OK" ng-click="listSubmit()">
<br>
</div>
<div>
<p>Selecionar um registo:</p>
<select ng-model="clienteSelecionado" ng-options="x.nome for x in clientes">
</select>
<table>
<tr>
<td>{{ clienteSelecionado.nome }}</td>
<td>{{ clienteSelecionado.morada }}</td>
</tr>
</table>
</div>
<hr>
<div>
<input type="button" value="View" ng-click="listView()">
<hr>
<table>
<tr>
<th>###</th>
<th>Nome</th>
<th>Morada</th>
</tr>
<tr ng-repeat=" y in clientes">
<td>{{ $index + 1 }}</td>
<td>{{ y.nome }}</td>
<td>{{ y.morada }}</td>
</tr>
</table>
</div>
<br>
<hr>
<br><br>
</div>
<script src="../lib/angular/angular.js"></script>
<script src="../lib/jquery/jquery.js"></script>
<script src="../js/app.js"></script>
<script src="../js/test.js"></script>
</body>
</html>
mydb2.sql
#//////////////////////////
#//
#// mydb2.sql
#//
#///////////////////////////
CREATE DATABASE MYDB2;
USE MYDB2;
CREATE TABLE CLIENTES2 (
id int NOT NULL auto_increment,
nome varchar (30) NOT NULL,
morada varchar (99) NOT NULL,
PRIMARY KEY (id)
);
GRANT ALL ON MYDB2.* to jspro2#localhost identified by 'jspro32';
Enjoy.

Cannot GET the requested API in express.js

Here is my express app code
app.get('/books',function(req,res){
var {keyword} =req.query;
connection.query('SELECT * from books', function (error, results, fields) {
if (error) throw error;
for(let result of results){
if(result.title === keyword){
res.send(result);
}
}
});
});
and the url i am requesting is http://......../books/keyword=intro. Where intro is the user input.
What i am trying to achieve here, is from an input in HTML, to take that info and send it to my API, so it can query my DB and get what i want.
But i get a 404 error, so i guess my api is configured incorrectly.
Is there a better way to implement what i am doing?
Is the keyword=intro even the correct way to query my db.
My html is like this
<!DOCTYPE html>
</head>
<body>
<div id="data">
<input type="button" id="button" value="Click"/>
<input type="text" id="search" >
</div>
<div id="search">
</div>
<script>
document.getElementById('button').addEventListener('click',getUserInput);
function getUserInput(event){
var userInput = document.getElementById("search").value;
if(userInput !== ""){
httpGetAsync(userInput);
}
}
function httpGetAsync(searchTerm){
var theUrl = 'books?keyword=' + searchTerm;
const xhttp = new XMLHttpRequest();
xhttp.open("GET", theUrl, true); // true for asynchronous
xhttp.send(null);
xhttp.onreadystatechange = processRequest;
function processRequest() {
if (xhttp.readyState == XMLHttpRequest.DONE);
var result = JSON.parse(xhttp.response);
console.log(result);
}}
</script>
</body>
In httpGetAsync function replace
var theUrl = 'books/keyword=' + searchTerm;
with:
var theUrl = window.location + '/books/keyword=' + searchTerm;
This answer is more of a comment unless it's acceptable. The statement that I want to write is too long for a comment.
In regards to my answer is that a valid way to write your prepared statement model? How I write my SQL models are like this and it works fine. Are you receiving any errors from your SQL syntax?
Notice the brackets after the ?.
selectBooks: function(data, callback) {
let keyword = "%" + req.query + "%";
connection.query("SELECT * FROM books WHERE title LIKE ?", [keyword], callback);
}

Need to parse live json file using Socket io

First a Heads Up! I am very new to the world of node.js and socket.io
I have a json file which contains following data for example:-
{
"football": {
"id": 1,
"home": "Liverpool",
"away": "Chelsea",
"score": "1-0",
"last scorer":"Gerrard"
}
}
This file is updated live on few seconds basis.
What i really want to achieve is to parse this json and update the same to html on client side, in addition to that i want to listen for any changes in json file and update the same again to html client side. How can i achieve this, sorry if the question seemed dumb enough, but any suggestion can help.
i finally found something and with a little tweak and researching other answers i have finally made a working code
First a brief review of what this code does
watches your json file (in this case sports.json)
if change detected then only reads the json file (in this case sports.json)
then emits the read json file to connected clients
on the client side the magic begins as soon as you make changes to your json file
PS: There is a discussion regarding fs.watch firing twice on manual editing and saving (i will come up with a workaround soon and update here)
Server Side
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var jf = require('jsonfile'); //jsonfile module
var fs = require('fs'); //require file system
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket) {
fs.watch("sports.json", function(event, fileName) { //watching my sports.json file for any changes
//NOTE: fs.watch returns event twice on detecting change due to reason that editors fire 2 events --- there are workarounds for this on stackoverflow
jf.readFile('sports.json', function(err, data) { //if change detected read the sports.json
var data = data; //store in a var
console.log('sent') //just for debugging
socket.volatile.emit('notification', data); //emit to all clients
});
});
});
http.listen(3000, function() { //listen to 3000
console.log('listening on *:3000');
});
Client Side:
<!doctype html>
<html>
<head>
<title>Socket.IO data</title>
<body>
<p id ="data">A data will appear here on change</p>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io.connect('http://localhost:3000'); //you can replace localhost with your public domain name too!!
socket.on('notification', function (data) {
$('#data').text(data.football.home); //Liverpool
});
</script>
</body>
sports.json File
{
"football": {
"id": 1,
"home": "Liverpool",
"away": "Chelsea",
"score": "1-0",
"last scorer":"Gerrard"
}
}
(Sorry for the little-detailed answer, I'm having computer problems and it's hard to do much; I'll edit it after they're resolved and everything stops crashing)
To look for a change in the file, try something like: Monitor file change through AJAX, how? or Check if file has changed using HTML5 File API
Server file:
var EventEmitter = require('events').EventEmitter;
var footballWatcher = new EventEmitter();
io.on('connection', function (client) {
//
//Existing Code
//
//Node.js Event listener:
footballWatcher.on('update', function(){
io.emit('footballUpdate', footballData);
});
//Code to look for a change in the file, use this in it:
if(updated){
footballWatcher.emit('update');
});
Client File:
//
//Existing Code (connections, methods, emits and responses, etc.)
//
socket.on('football', function(footballJSONData){
//JSON interpretation
});

node.js storing previous form data, and rerunning previous mysql queries every time form is submitted with new data

I am having a problem with node.js where every time I run a query, it reruns all the previous queries ran, along with the new one.
More specifically: I have a form with three fields: first name, last name, email. When I submit that form, I want to:
- check if the user already exists in the database (I do this with a SQL query on the email address).
- if client exists, display a message on the form that the client can't be added.
- if the user DOESN't exists, add the client to the database and display a 'Successfully added client' message on the form.
Seems easy, right?
What is happening is that for the first new user I add, everything is fine. Then I add a second new user, but what happens in the database is that it adds TWO entries: it re-adds the first new user, and the second as well. If I try to add a third user, it ends up running 3 'INSERT INTO' queries, adding the first user (a third time) and the second user again, then the third. And so on...
It's like there is some storage somewhere that I am not clearing out between form submissions - but I'm not using a session here, so I don't know where this form data is being persisted!
Any thoughts? I am very new to node.js and I think I must be missing something very fundamental, but I can't see it.
Here is the javascript and form from my 'index.html' file:
<script type="text/javascript">
$(document).ready(function(){
$("#new_client").submit(function(){
var form = $(this);
//remove previous message section
form.siblings('p').remove();
$.getJSON(
form.attr('action'),
form.serialize(),
function (result){
if (result.success == true){
$(form).before("<p>Success: "+result.message+"</p>");
}
else if (result.success == false){
var html = "";
for (var i = 0; i < result.message.length; i++){
html += "<p>Failed: "+result.message[i]+"</p>";
}
$(form).before(html);
}
}); //end $.getJSON
return false;
});
});
</script>
<body>
<form id="new_client" action="/add_client" method="get">
<!-- NOTE: we need to use method="get" for getJSON -->
<input type="text" name="first_name" placeholder="Client first name">
<input type="text" name="last_name" placeholder="Client last name">
<input type="text" name="email" placeholder="Client email">
<button type="submit">Add Client</button>
</form>
</body>
And here are parts of my nodejs code (server.js):
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
var querystring = require('querystring');
var mysql = require('mysql');
var events = require('events');
var Validator = require('validator').Validator;
var eventEmitter = new events.EventEmitter();
var db = mysql.createConnection({
//host:'localhost',
port: 8889,
user: 'root',
password: 'root',
database: 'test_database'
});
server = http.createServer(function (request, response){
var pageUrl = url.parse(request.url).pathname;
if(pageUrl === '/add_client'){
var dataQuery = url.parse(request.url).query;
var formData = querystring.parse(dataQuery);
//set up event listener for 'add client result'
eventEmitter.on('addClientResult', function (result){
response.end(JSON.stringify(result));
});
//set up listener for existing client check
eventEmitter.on('clientIsNewResult', function (result){
if (result.success === false){
response.end(JSON.stringify(result));
}
else {
//this will trigger the 'addClientResult' event
addClient(db, formData.first_name, formData.last_name, formData.email);
}
});
//set up event listener for validated data
eventEmitter.on('validateDataResult', function (result){
if (result.success === false)
response.end(JSON.stringify(result));
else{
//trigger 'clientIsNewResult' event
clientIsNew(db, formData.email);
}
});
// trigger the validateDataResult event
validateData(formData.first_name, formData.last_name, formData.email);
} //end 'add_client'
else { ... code for other actions and where we start the response object... }
}); //end of server object
server.listen(8080);
function clientIsNew(db, email){
db.query('SELECT * FROM clients WHERE email=?', [email],
function (errors, results, fields) {
if (errors) throw errors;
//console.log(this.sql);
if (results.length > 0){
query_result = {
'success': false,
'message': ['There is already a client with this email address!']
}
}
else {
query_result = {
'success': true,
'message': 'This is a unique user'
};
}
eventEmitter.emit('clientIsNewResult', query_result);
});
}
function addClient(db, first_name, last_name, email){
//the only time we should get here is when we want to create a new user
//so we should only get here when 'clientIsNewResult' is triggered and gets
// a result of true... at least that is the intention!
db.query('INSERT INTO clients SET first_name=?, last_name=?, email=?, created_at=NOW();',
[first_name, last_name, email],
function (errors, results, fields) {
if (errors) throw errors;
//console.log(this.sql);
insert_result = {
'success': true,
'message': 'Client is added'
}
eventEmitter.emit('addClientResult', insert_result);
}
);
}
function validateData(first_name, last_name, email){
... validates info, no problems with this ...
eventEmitter.emit('validateDataResult', result);
}
console.log('Server running at http://localhost:8080/');
OK, I hope that wasn't too much, I deleted a lot of comments and other console.log lines I had in there as well.
Please let me know if I need to post more, or less, or if I've forgotten something.
Thanks in advance for your help!
Move you Event emitter to inside you http request
move
var eventEmitter = new events.EventEmitter();
to
server = http.createServer(function (request, response){
var pageUrl = url.parse(request.url).pathname;
var eventEmitter = new events.EventEmitter();
Finally got some guidance from a mentor. My problem is that every time I send data to the server, I am creating another event listener, but the previous event listener(s) still exist. So the second time I submitted the form, there were two event listeners on the same event; the third time, there were three... ect.
Solution: major refactor of code, to not use so many. ALSO: changing eventEmitter.on() to eventEmitter.once() for the addClientResult event, which is the only event listener left. After all, I only want to add a client once each time I submit data to the server.