How to unite .pug and node file - node.js

I'm all new to pug (jade).
I've got the following markup which does exactly what I want for the html part:
doctype html
html(lang="en")
head
title= "Project BOT"
body
h1 My project BOT
.container
.row
- for (var i=0; i<5; i++){
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id
p.restaurant_name
p.discount
p.timestamp
button
.back
- }
I've got a nodejs file where I establish connection to a database and just output the DB contents. Looks as follows:
// mysql connection credentials
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'host',
user: 'user',
password: 'pass',
database: 'dbname'
});
// connect to database
connection.connect(function (err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
connection.query('SELECT * from botrequests',
function (error, results, fields) {
if (error) throw error;
console.log(results);
});
What I wanna do is to output database fields in the for loop I've got in pug. What's the right (or the possible) way to do so?
Loop is gonna look like:
- for (var i=0; i<results.length; i++){
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id results[i].id
p.restaurant_name results[i].name
p.discount results[i].discount
p.timestamp results[i].time
button
.back
- }
Thanks!

Simple server using express:
var express = require('express');
var app = express();
app.set("view engine","jade")
app.get('/', function (req, res) {
// mysql connection credentials
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'host',
user: 'user',
password: 'pass',
database: 'dbname'
});
// connect to database
connection.connect(function (err) {
if (err) {
return err;
}
console.log('connected as id ' + connection.threadId);
connection.query('SELECT * from botrequests',
function (error, results, fields) {
if (error) throw error;
res.render('JadeFileName', { results: results });
});
});
});
Jade can then loop through items internally:
if results && results.length
each r in results
.item col-md-3 col-sm-12 #content
.card
.front
p.telegram_id #{r.id}
p.restaurant_name #{r.name}
p.discount #{r.discount}
p.timestamp #{r.time}
button
.back

Related

When new user connects the previous connection becomes the new user

I've been playing around a bit with NodeJS and recently socket.IO, I come from PHP development and try to understand really how to work with Node and socket.IO
I started building a chat app and when I were to test it on different devices I noticed that when I for instance log in to another account through my phone, the browser window updates and gets the same user as I logged into on my phone
index.html
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: 0.5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<div id="chatLogin">
<input type="text" name="password" id="username" placeholder="Username..." /><br>
<input type="password" name="password" id="password" placeholder="Password..." /><br>
<button id="chatLoginBtn">Login / Register</button>
</div>
<div id="chatWindow">
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(function () {
var socket = io();
$(document).ready(function(){
$("#chatWindow").hide();
$("#chatLoginBtn").click(function(){
socket.emit('loginForm', {
username: $("#username").val(),
password: $("#password").val()
});
});
});
socket.on('returnValue', function(msg) {
var html = '<ul id="messages"></ul>' +
'<form id="sendMsg" action="">' +
'<input id="m" autocomplete="off" /><button>Send</button>' +
'</form>';
$("#chatLogin").html("").hide();
$("#chatWindow").html(html).show();
$('#sendMsg').submit(function(e) {
e.preventDefault(); // prevents page reloading
var time = Date.now();
var msg = $("#m").val();
var data = [time, msg];
socket.emit('chat', data);
$('#m').val('');
return false;
});
});
socket.on('chat', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
</body>
</html>
index.js
var app = require('express')();
var http = require('http').createServer(app);
var phpPass = require('node-php-password');
var mysql = require('mysql');
var io = require('socket.io')(http);
var cookieParser = require('cookie-parser');
var session = require('express-session');
// DECLARE the variables we will be using
// These does not change
let userCount = 0;
// These are declared to be later set
var displayName;
var userDataID;
// POOL MySQL Connection
var pool = mysql.createPool({
connectionLimit : 100,
host : 'localhost',
user : 'root',
password : '....',
port : '3306',
database : '....',
debug : false
});
// session & cookieParser
/*var sessionMiddleware = session({
secret: "keyboard cat"
});
io.use(function (socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.use(cookieParser());*/
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var hashPassword;
function checkUser(user, Password, userID) {
pool.getConnection(function(error,connection) {
connection.query("SELECT password FROM accounts WHERE `username` = '"+user+"' LIMIT 1",function(error,rows){
if (!error) {
var hashPassword = rows[0].password;
if (phpPass.verify(Password, hashPassword)) {
console.log(Password);
console.log(hashPassword);
console.log("Went well");
// UPDATE user database with current socketID
connection.query("UPDATE accounts SET `socketID` = '"+userID+"' WHERE `username` = '"+user+"'",function(error,result){
connection.release();
if (!error) {
connection.query("SELECT id,displayName,username,email,fullName,dateofBirth,created,lastSignedIn FROM accounts WHERE socketID = '"+userID+"' LIMIT 1",function(error,userData){
if (!error) {
displayName = userData[0].displayName;
userDataID = userData[0].id;
console.log("Current user: " + userData[0].displayName);
} else {
console.log("Error" + error);
}
});
console.log("No error" + result);
} else {
console.log("We found error" + error);
}
});
// send to function to gather all needed info from database and save for the current session
return true;
} else {
console.log("Wrong pass");
return false;
}
console.log(hashPassword);
} else {
console.log(error);
return false;
}
});
connection.on('error', function(error) {
});
});
return true;
};
io.on('connection', (socket) => {
var req = socket.request;
var userID = socket.id;
// When connection is inited
userCount++;
console.log('User connected' + userCount);
// Take the data from login and pass to check if it is valid
socket.on("loginForm", function(data){
const user = data.username,
pass = data.password;
//console.log(checkUser(user, pass));
if (checkUser(user, pass, userID)) {
io.emit('returnValue', 'hi');
}
});
function joinRoom(room) {
socket.join(room);
console.log("Joined " + room);
return io.emit('chat', "Joined new room " + room);
}
socket.on('join', (data) => {
socket.join(data);
console.log("Joined " + data);
});
socket.on('chat', (data) => {
/* Array: Data;
[0] Time
[1] Message
[2] socketID
[3] User
*/
var msg = data[1];
var time = data[0];
// Calc time
var date = new Date(time);
var hours = date.getHours();
var minutes = date.getMinutes();
var formatted = hours + ":" + minutes;
if (minutes < 10) return minutes = "0" + minutes;
var dateFormatted = "[" + formatted + "] ";
//data.push(user);
pool.getConnection(function(error,connection) {
connection.query("INSERT INTO `chat_messages` (userID, socketID, message, time) VALUES ('"+userDataID+"', '"+userID+"', '"+msg+"', '"+time+"')",function(error,rows){
connection.release();
if (!error) {
console.log("Success");
} else {
console.log(error);
}
});
});
if (msg.startsWith('/me')) return io.emit('chat', dateFormatted + displayName + msg.substring(3));
if (msg.startsWith('/join')) return joinRoom(msg.substring(6));
if (msg.startsWith('/rooms')) return console.log(io.sockets.adapter.rooms);
return io.emit('chat', dateFormatted + displayName + ' said: ' + msg);
//console.log(displayName + 'said:' + msg);
});
// When user disconnects
socket.on('disconnect', () => {
userCount--;
console.log('User disconnected!' + userCount);
});
});
http.listen(3000, () => {
console.log('Listening on *:3000');
});
I do not get any errors and it counts the number of users correctly
The problem is that the user first logged in gets switched to the last logged in user
How do I make the user session unique and so multiple clients can be logged in into different accounts?
I noticed an issue: var userDataID;
It's a global variable. Each time a new user log ing, the userDataID will be updated. It's always the ID of the newest logged user. Then, all new messages will be stored in the database with the userDataID.
EX:
- Log in by account A on window, the userDataID = 1;
- send some messages to server, these message will be stored with userID = 1
- Log in by account B on iphone, the userDataID will be updated, it's = 2 now.
- send some messages from windown & iphone. all these message will be stored with userID 2.
I think that's the error you got.
Should store userID in cookie or session.

private chat with socket.io in node.js

I'm trying to create a chat system, where a user can send message to everybody (and this message is displayed in the div with id "chat") and I've achieved this feature. Now I'd like to implement a private chat. A user can click on another user's name on the right column (which shows all logged users), once he clicked on a username a little window will appear (div with class "chatpopup") and in this window there is a submit button and an input text to be filled with a message, once submit button has been clicked the message should be sent to the other user.
This is what I have, if I click on a user (on the right side of the screen) the little window (chatpopup) is shown but when I try to submit the form inside this little window the app crashes.
I'd also like to receive some hints about building a private chat, for example how can I open a new window (with the message receive) in the client side of the user that should receive the message?
index.html
<html>
<head>
<title>Chat with socket.io and node.js</title>
<style>
#contentWrap
{
width:100%;
display: none;
}
#chatWrap {float: left; width:80%;}
#chat
{
height:500px;
width:96%;
border: 1px #000 solid;
padding-left:2%;
padding-right:2%;
}
#users
{
margin-left:82%; width:15%;
height:500px;
border: 1px #000 solid;
text-align:right;
}
#send-message {margin-top:3%; width:100%;}
#message {width:80%;}
.err1r{ padding-top:1%;
color: red;
}
.whisper{
color: gray;
font-style: italic;
}
p.sideusername:nth-child(even) {background-color:#FAFAFA; padding-bottom:5%; padding-top:5%;}
p.sideusername:nth-child(odd) {background-color: #f5f5f0; padding-bottom:5%; padding-top:5%;}
.chatpopup {width:350px; height: 250px; background-color:blue;}
#interlocutore {background-color:red; height: 30px; text-align: left;}
#msgspace {height:150px; background-color:yellow;}
</style>
</head>
<body>
<div id="nickWrap">
<p>Enter a username:</p>
<p id="nickError"></p>
<form id="setNick">
<input size="35" id="nickname"></input>
<input type="submit"></input>
</form>
</div>
<div id="contentWrap">
<div id="chatWrap">
<div id="chat"></div>
<form id="send-message">
<input size="35" id="message"></input>
<input type="submit"></input>
</form>
</div>
<div id="users"></div>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
jQuery(function($){
var socket = io.connect();
var $nickForm = $('#setNick');
var $nickError = $('#nickError');
var $nickBox = $('#nickname');
var $users = $('#users');
var $messageForm = $('#send-message');
var $messageFormPopup = $('#send-message-popup');
var $messageBox = $('#message');
var $messageBoxPopup = $('#messagePopup');
var $chat = $('#chat');
$nickForm.submit(function(e){
e.preventDefault();
socket.emit('new user', $nickBox.val(), function(data){
if(data){
$('#nickWrap').hide();
$('#contentWrap').show();
} else{
$nickError.html('That username is already taken! Try again.');
}
});
$nickBox.val('');
});
socket.on('usernames', function(data){
$users.empty();
for(var i=0; i < data.length; i++){
$users.append('<p class="sideusername">' + data[i] + "</p>");
}
});
$messageForm.submit(function(e)
{
e.preventDefault();
socket.emit('send message', $messageBox.val(), function(data)
{
});
$chat.append('<span class="error">' + data + "</span><br/>");
$messageBox.val('');
});
$messageFormPopup.submit(function(e)
{
e.preventDefault();
socket.emit('send popup message', $messageBoxPopup.val(), function(dataPopup)
{
});
$messageBoxPopup.val('');
});
socket.on('load old msgs', function(docs){
for(var i=docs.length-1; i >= 0; i--){
displayMsg(docs[i]);
}
});
socket.on('new message', function(data){
displayMsg(data);
});
function displayMsg(data){
$chat.append('<span class="msg"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
}
socket.on('whisper', function(data){
$chat.append('<span class="whisper"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
});
$(document).on("click", ".closepopup", function() {
$(this).parents('.chatpopup').hide();
});
$(document).on("click", ".sideusername", function()
{
var interlocutore = $(this).text();
$chat.append('<div class="chatpopup"><table><tr><td id="interlocutore"></td><td><p class="closepopup">X</p></td></tr><tr><td colspan="2" id="msgspace"></td></tr><tr><td colspan="2"><form id="send-message-popup"> <input size="35" id="messagePopup"></input><input type="submit"></input></form></td></tr></table></div>');
$('#interlocutore').append(interlocutore);
});
});
</script>
</body>
</html>
app.js
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
mongoose = require('mongoose'),
users = {};
server.listen(3000);
mongoose.connect('mongodb://localhost/chat', function(err)
{
if(err)
console.log(err);
else console.log('Connected to mongodb!');
});
var chatSchema = mongoose.Schema(
{
nick: String,
msg: String,
created: {type: Date, default: Date.now}
});
var Chat = mongoose.model('Message', chatSchema);
app.get('/', function(req, res)
{
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket)
{
var query = Chat.find({});
query.sort('-created').limit(8).exec(function(err, docs)
{ // carico gli ultimi 8 messaggi in ordine di data
if(err) throw err;
socket.emit('load old msgs', docs);
});
socket.on('new user', function(data, callback)
{
if (data in users)
callback(false);
else
{
callback(true);
socket.nickname = data;
users[socket.nickname] = socket;
updateNicknames();
}
});
function updateNicknames()
{
io.sockets.emit('usernames', Object.keys(users));
}
socket.on('send message', function(data, callback)
{
var msg = data.trim();
var newMsg = new Chat({msg: msg, nick: socket.nickname});
newMsg.save(function(err)
{
if(err) throw err;
io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
});
socket.on('disconnect', function(data)
{
if(!socket.nickname) return;
delete users[socket.nickname];
updateNicknames();
});
});
socket.on('send popup message', function(data, callback)
{
/*var msgPopup = dataPopup.trim();
if (msgPopup !== "")
users[interlocutore].emit('whisper', {msg: msgPopup, nick: socket.nickname});
*/
var msg = data.trim()+" hello";
var newMsg = new Chat({msg: msg, nick: socket.nickname});
newMsg.save(function(err)
{
if(err) throw err;
io.sockets.emit('new message', {msg: msg, nick: socket.nickname});
});
socket.on('disconnect', function(data)
{
if(!socket.nickname) return;
delete users[socket.nickname];
updateNicknames();
});
});
});
To create a private chat using socket.IO, you need to first understand how rooms in socket.IO work. You can find loads of tutorials. You can also see this post for help.
Now you need to extend this functionality to create a private chat system. In order to do so, you need to have an unique id for each client that is either connected or is online. socket.id is an unique key that each client gets upon joining the chat.
On the client side, you can emit a name along with the message to the server. You do so like this:
socket.emit('privateMessage', 'theUserName', message);
On the server side, you could manage an array of the users who are connected and save their unique usernames or id's.
var connectedClients = {};
So each time an user connects to the chat, (for which you are probably using the new user event), save the user's id in the connectedClients.
connectedClients[username] = socket.id;
Where username is the name that is sent to the server while an user is connecting to the chat system. (I hope you know how to do this. If not, do ask me.)
Then we make a listener to listen to the privateMessage event and emit to the message to that particular user, we do:
socket.on('privateMessage', function(to, message) {
var id = connectedClients[to];
io.sockets.socket(id).emit('sendPrivateMessage', socket.username, message);
});
Finally, on the client side, your listener for the sendPrivateMessage receives the message and you can update your view accordingly.
The idea is that the server saves each socket connected to it by the username: users[socket.nickname] = socket;
so whenever a user send a message to another user - you should emit an event - send to that the username of the other user - take the socket of that user and emit him a message:
client:
socket.emit('sendPrivate','someusername','message');
socket.on('privateMsg',function(from,msg){
//write private message from user 'from'
});
server:
socket.on('sendPrivate',function(to,msg){
users[to].emit('privateMsg',socket.username,msg);
});

Mongoose giving me undefined error

OK i don't get this one bit. it was actually working just fine a while ago but now i'm getting the following error:
ERROR
azura#AzuraMain:~$ nodejs /home/azura/Desktop/dbWrite.js
Connection to database has been established
Server is up
/home/azura/Desktop/dbWrite.js:94
res.send("<h1>Hello</h1> " + id + " " + data.name);
^
TypeError: Cannot read property 'name' of undefined
at /home/azura/Desktop/dbWrite.js:94:53
at /home/azura/node_modules/mongoose/node_modules/kareem/index.js:160:11
at Query._findOne (/home/azura/node_modules/mongoose/lib/query.js:1145:12)
at /home/azura/node_modules/mongoose/node_modules/kareem/index.js:156:8
at /home/azura/node_modules/mongoose/node_modules/kareem/index.js:18:7
at process._tickCallback (node.js:415:13)
I dont understand why i would be getting this error.
Here's my code:
SERVER CODE
var mongoose = require("mongoose");
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
//Use These Modules
app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
});
//Create the homepage of the server
mongoose.connect("mongodb://localhost:27017/NEW_DB1");
console.log("Connection to database has been established");
//Connect to the database
var collectedData = new mongoose.Schema({
ipAddress: String,
name: {
type: String,
unique: false
}
});
var collectionOfData = mongoose.model("dataType", collectedData);
//Create the mongoose schema
io.on("connection", function (socket) {
//Check for connection with socket.io
socket.on("name", function (e) {
//Check for "name" with socket.io
var ip = socket.request.socket.remoteAddress;
//Check the ip address of user
var dataBase = mongoose.connection;
var Maindata = new collectionOfData({
ipAddress: ip,
name: e
});
//Create the Schema with the requested name and ip
Maindata.save(function (err, Maindata) {
if (err) {
return console.error(err);
} else {
console.dir(Maindata);
}
});
//Save this into the database
});
});
app.get("/mix", function (req, res) {
collectionOfData.find(function (err, data) {
res.send(data);
});
});
//Just a test directory /mix
app.get("/:uniqueURL", function (req, res) {
var id = req.params.uniqueURL;
//Create a unique URL
collectionOfData.findOne({
_id: id
}, function (err, data) {
res.send("<h1>Hello</h1> " + id + " " + data.name);
//This is where the issue derives from data.name is undefined? I Defined it up there and it seems to work for a second until the server crashed because of it
});
//Send the data to the requested page
});
http.listen(10203, function () {
console.log("Server is up");
});
//Create the HTTP Server
HTML CODE
<html>
<body>
<form id="chooseName">
<input class="center-block" id="name" placeholder="Post whatever the fuck you want" />
</form>
<script src="/socket.io/socket.io.js">
</script>
<script src="http://code.jquery.com/jquery-1.11.1.js"> </script>
<script>
var socket = io();
$("#chooseName").submit(function (e) {
e.preventDefault();
socket.emit("name", $("#name").val());
document.write("cool go to http://173.78.185.247:10203/mix to see what you have contributed to");
});
//Send data to the server where it gets read with socket.on("name", Do Something
</script>
</body>
</html>
why does this happen? all i want is to make data.name print out the requested name of the user. it seems to work for a second but then the server just crashes.
if there is no matching document in collection data then findOne() can provide null in data object.
debug by printing id, err, and data.

Why during $save() it generates a new entry in the mongoDB with a string _id?

MEAN stack newbie here. Probably asking a silly question.
As an exercise, I have been trying to implement a prototype SPA which shows a series of task cards on the screen (kinda like Trello).
For now, each card has 4 fields:
_id: ObjectId
content: String
workflow: String
state: String
I am using MongoDB for the database (entered some test data using Robomongo), I have node.js installed on my machine, as well as Express.js.
My server.js file looks like the following:
var express = require('express'),
cards = require('./routes/cards');
var app = express();
app.configure(function() {
app.use(express.logger('dev'));
app.use(express.bodyParser());
});
app.get('/cards', cards.findAll);
app.get('/cards/:id', cards.findById);
app.post('/cards', cards.addCard);
app.put('/cards/:id', cards.updateCard);
app.listen(3000);
console.log('Listening on port 3000...');
My routes/cards.js on the server side look like the following:
var mongo = require('mongodb');
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
var server = new Server('localhost', 27017, {auto_reconnect: true});
var db = new Db('mindr', server);
db.open(function(err, db) {
if(!err) {
console.log("Connected to 'mindr' database");
db.collection('cards', {strict:true}, function(err, collection) {
if (err) {
console.log("The 'cards' collection doesn't exist.");
}
});
}
});
exports.findById = function(req, res) {
var id = req.params.id;
console.log('Retrieving card: ' + id);
db.collection('cards', function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
exports.findAll = function(req, res) {
db.collection('cards', function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
});
};
exports.addCard = function(req, res) {
var newCard = req.body;
console.log('Adding card: ' + JSON.stringify(newCard));
db.collection('cards', function(err, collection) {
collection.insert(newCard, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred'});
} else {
console.log('Success: ' + JSON.stringify(result[0]));
res.send(result[0]);
}
});
});
}
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
exports.deleteCard = function(req, res) {
var id = req.params.id;
console.log('Deleting card: ' + id);
db.collection('cards', function(err, collection) {
collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
if (err) {
res.send({'error':'An error has occurred - ' + err});
} else {
console.log('' + result + ' document(s) deleted');
res.send(req.body);
}
});
});
}
When I get the cards from the DB in my AngularJS controller, everything goes fine. All the cards are correctly displayed on the screen. This is the code that gets the cards:
var mindrApp = angular.module('mindrApp', ['ngResource'])
mindrApp.controller('WorkflowController', function ($scope, $resource) {
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"});
$scope.cards = CardService.query();
});
On each card there are some buttons that can be used to change the state of the card to the next state available in the workflow (as defined by the current state available actions).
When the button is clicked, the card id and the next state are passed to a function in the controller:
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-default"
ng-repeat="currentAction in currentState.actions | filter:{default:true}"
ng-click="processCard(currentCard._id, currentAction.next)">
{{currentAction.name}}
</button>
</div>
And this is the processCard function in the controller:
$scope.processCard = function(id, nextState) {
var currentCard = CardService.get({cardId: id}, function(){
currentCard.state = nextState;
currentCard.$save();
});
};
What's happening is that when I click the button, instead of changing the state of the current card, a new card is created with an id field of type String. This is the output of the server:
Retrieving card: 52910f2a26f1db6a13915d9f
GET /cards/52910f2a26f1db6a13915d9f 200 1ms - 152b
Adding card: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
Success: {"_id":"52910f2a26f1db6a13915d9f","content":"this is some content for this really cool card","workflow":"simple","state":"completed"}
POST /cards 200 1ms - 150b
Any idea why this is happening? Why is it calling the addCard function on the server instead of calling the updateCard function?
The $save() action of a $resource object use POST as default request type (Read more here). So in your case, a POST request to the route /cards/:id was called, so as a result, a new card was created.
Either create a new route entry to handle POST update request in server.js
app.post('/cards/:id', cards.updateCard);
Or add another action that use PUT to your CardService and call it when you want to update your card
var CardService = $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{ update: { method: 'PUT' } }
);
// update the card
...
currentCard.$update();
Ok, so I figured it out. The two problems I were having were:
1) instead of updating the existing item in the database, it was creating a new one with the same ID but in string format instead of using the ObjectId format.
2) any time I called $update, it would not append the ID to the path, but always PUT to /cards.
So here are the solutions to each of the problems.
1) This is really a hack that assumes that ALL id are in ObjectId format. I don't like this solution but for now it works and I am sticking to it. All I had to do was to add the line that converts the card._id back to ObjectId format to the updateCard function inside the cards.js file on the server side.
exports.updateCard = function(req, res) {
var id = req.params.id;
var card = req.body;
console.log('Updating card: ' + id);
console.log(JSON.stringify(card));
card._id = new BSON.ObjectID.createFromHexString(card._id); // HACK!
db.collection('cards', function(err, collection) {
collection.update({'_id':new BSON.ObjectID(id)}, card, {safe:true}, function(err, result) {
if (err) {
console.log('Error updating card: ' + err);
res.send({'error':'An error has occurred'});
} else {
console.log('' + result + ' document(s) updated');
res.send(card);
}
});
});
}
2) This was a two part fix. First, I had to modify the services.js file to explicitly say that I want to use update via PUT:
var mindrServices = angular.module('mindrServices', ['ngResource']);
mindrServices.factory("Card", ["$resource",
function($resource) {
return $resource("http://localhost:3000/cards/:cardId", {cardId:"#id"},
{
query: {method: "GET", isArray:true},
update: {method: "PUT"}
}
);
}]);
Next, I was under the assumption that simply calling currentCard.$update() would grab the ID from the calling instance, instead I have to explicitly pass in the ID as follows:
var mindrControllers = angular.module('mindrControllers', []);
mindrControllers.controller('CardsController', ["$scope", "Card",
function ($scope, Card) {
$scope.cards = Card.query();
console.log("cards populated correctly...");
$scope.processCard = function(currentCard, currentAction) {
console.log("processCard: card[" + currentCard._id + "] needs to be moved to [" + currentAction.next + "] state... ");
currentCard.state = currentAction.next;
currentCard.$update({cardId: currentCard._id}); // passing the ID explicitly
}
This is the output I get on the server side:
Updating card: 52910eb526f1db6a13915d9c
{"_id":"52910eb526f1db6a13915d9c","content":"this is some content for this really cool card","workflow":"simple","state":"backlog"}
1 document(s) updated
PUT /cards/52910eb526f1db6a13915d9c 200 4ms - 111b

Where should I do database queries and why am I not getting the results of the queries?

I'm new to node.js and the express framework.
Can anyone tell me if I'm doing this correctly?
I created a database.js as a module, and the code contains:
var mysql = require('mysql'),
dateFormat = require('dateformat'),
db = require('./dashboard');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'selenium',
timezone: '-07:00'
});
exports.selectalldate = function() {
connection.query('SELECT * FROM date', function (err, rows, fields) {
if (err) {
console.log(err);
}
if(rows.length > 0) {
for(i = 0; i < rows.length; i ++) {
rows[i].date = dateFormat(rows[i].date, "yyyy-mm-dd")
}
return rows;
} else {
return false;
}
});
}
I required it in my app.js, and when I call the selectalldate() to get all the dates from the database in app.js and see what's the results. I get undefined. What am I doing wrong here?
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, fs = require('fs')
, file = __dirname + '/test2'
, get = require('./routes/get')
, db = require('./routes/database')
;
app.get('/dashboard', function(req, res) {
var datee = db.selectalldate();
console.log(datee);
res.render('dashboard', {title: 'Selenium Dashboard', date: datee});
});
That's because the asynchronous nature of Node. Everything that has networking involved (DB queries, webservices, etc) is async.
Because of this, you should refactor your selectalldate() method to accept an callback. From that callback you'll be able to render your template successfully with the data fetched from the DB.
In the end, it'll be something like this:
exports.selectalldate = function(callback) {
connection.query('SELECT * FROM date', function (err, rows, fields) {
if(rows.length > 0) {
for(i = 0; i < rows.length; i ++) {
rows[i].date = dateFormat(rows[i].date, "yyyy-mm-dd")
}
}
callback(err, rows);
});
}
app.get('/dashboard', function(req, res) {
db.selectalldate(function(err, datee) {
if (err) {
// Handle the error in some way!
return;
}
res.render('dashboard', {title: 'Selenium Dashboard', date: datee});
});
});

Resources