I have a server in Node.js and I use Express to make a web app.
My server (app.js) gets data from a form (by Ajax post method) and I want that it proceeds this data by using the code of another file (anotherfile.js).
I used this solution: https://stackoverflow.com/a/950146/3303704 and I included this code in my app.js file:
app.post('/', function(req, res) {
$.getScript("anotherfile.js", function(){
alert("Script loaded and executed.");
});
});
But Node.js returns me that "has no method 'getscript'".
Idea of the cause and solution? Thanks!
You appear to be trying to use jQuery in node.
The solution you have linked to is a solution for front-end.
Use require() in node.
Try reading this article: Node.js, Require and Exports. It explains that for instance if you define this in one file called user.js:
var User = function(name, email) {
this.name = name;
this.email = email;
};
module.exports = User;
You can do this in another:
var user = require('./user');
var u = new user.User();
Related
I am trying to send a variable from my client-side JavaScript file to my server-side app.js file. I know that you can get a value from something like a form input field using methods such as the one below (using Express):
var express = require('express');
var app = express();
var path = require('path');
let cityResponse;
app.post('/city', function(req,res) {
cityResponse = {
user_name: req.body.userName
}
res.sendFile(path.join(__dirname, '/client/city/index.html'));
});
But I would like to get a value not directly from the HTML, but from the JavaScript file that the HTML is attached to.
As well as this, I am currently using Socket.io to send the data from the server to the client, and vice versa, using a window.onload to let the server know when the page is ready:
index.js
window.onload = function() {
socket.emit('cityPageReady');
console.log("city page ready");
};
socket.on('cityPageInfo', function(cityResponse) {
console.log('city page info received');
console.log(cityResponse);
console.log(cityResponse.user_name);
userName = cityResponse.user_name;
document.getElementById("name").innerHTML = userName;
});
app.js
var city = io.of('/city').on('connection', (socket) => {
console.log('A user has connected!');
socket.on('cityPageReady', function() {
socket.emit('cityPageInfo', cityResponse);
console.log('city page ready recieved');
});
});
This works, but many people have said that this is overkill, or as one person put it, "using a hammer to kill a bee". Ideally, I'd like to use the optimal method. I do know that template engines can achieve this, but I do not want to have to rewrite all my HTML just to be able to send a single variable to the server.
To reiterate, my questions are:
How would I get a variable from the client-side JavaScript file (not the HTML)?
What is the best way to send these variables back over to client-side?
Any help would be greatly appreciated.
I have a backend service that I would like to use as a single point of entry for my web application, and dynamically assign a database path based on the user login.
I realize that this is not a scalable solution. I intend to use it during a testing period with several clients (accessing the ALPHA database), and also setting up a demo (accessing the SAND database).
I have the following module that I have written as a simple test to see if the login is for the demo user, all other logins will go to the other resource:
config.js
var express = require('express');
var app = express();
module.exports.dbPath = function (login){
console.log('login - ', login);
if (login === 'demo#mysite.com'){
return process.env.DB_SAND;
} else {
return process.env.DB_ALPHA;
}
};
My question is, how can I manage each unique login and assign a globally accessible reference for that session to direct each user session consistently to the correct database?
Am I overcomplicating this? If there is a different approach that would be a better practice I would welcome a suggestion in another direction.
I would use it as a middleware, and attach it to the req object for each user, something similar this:
module.exports = {
dbPath: function(req, res, next){
var login = req.body.login;
console.log('login - ', login);
if (login === 'demo#mysite.com'){
req.dbPath = 'DB_SAND';
} else {
req.dbPath = 'DB_ALPHA';
}
next();
}
};
I'm learning Node.js. At this time, I am using ES6, Node, and Express. I am concerned about the scope of my view model. At this time, I have the following:
server.js
// setup the routing
var routes = require('./routes');
app.use('/', routes.home);
The routes are properly registering. I have my routes defined in $projectDir/routes/home.js. That file looks like this:
home.js
var router = require('express').Router();
/* GET the main page. */
router.get('/', function(req, res) {
var viewModel = require('../viewModels/home/index');
res.render('home/index', viewModel);
});
/* GET the contact page. */
router.get('/contact', function(req, res) {
var viewModel = require('../viewModels/home/contact');
res.render('home/contact', viewModel);
});
/* POST contact information */
router.post('/contact', function(req, res) {
// ?
});
That approach works just fine. I've defined my view models at $projectDir/viewModels/home/index.js and $projectDir/viewModels/home/contact.js.
index.js
var viewModel = {
title: '',
constructor() {
this.title = 'Welcome';
}
};
module.exports = viewModel;
contact.js
var viewModel = {
title: '',
emailAddress: '',
constructor() {
this.title = 'Contact Us';
}
};
module.exports = viewModel;
I have concerns around the scope of view model. First, I'm using module.exports = viewModel; in two separate files. Is this ok? Or should I name the variables something like indexViewModel and contactViewModel? Also, when a POST happens, how do I populate use the view model with the values that the user entered into a form? For example their email address?
As far as node is concerned, you can use the same name viewModel in more than one file. But for your own sanity and clarity of thought I'd recommend using different names, as you suggested. When you asked the question, "how do I populate the view model?", I had to go back and read through the code for a couple of seconds to see which view model you meant. When you program grows from 40 lines to 4000 lines it will become a lot hard to keep the models straight if they all have the same name.
As for the POST data, you can access the POST data using the req.body property. This questions is already answered here: How do you extract POST data in Node.js?
I'm building a larger web app, where the routes are divided into separate files.
All routes need a connection to the db, and therefore all of them require mongoskin, which is the module I'm using for MongoDb. Like this:
var mongo = require('mongoskin');
But soon after I realised that only require the mongoskin wasn't enough for the routes to be able to talk to the db. Because in my main app.js file I also made additional "configurations".
db = mongo.db('mongodb://localhost/dbName', {native_parser:true});
db.open(function(err) {
if (!err) {
console.log('Connected to mongodb://localhost/dbName');
}
});
db.bind('clients');
db.bind('invoices');
I needed this db object to be shared aswell...
My first attempt was to wrap the route file in a exported function that takes an argument. This argument is passed in when I require the routes.js in my main app.js. This worked out fine, but I wasn't really fond of this solution... I think it became a bit messy.
My second approach, which I'm using right now, is to make a separate module of the whole db object.
var mongo = require('mongoskin');
var db = null;
module.exports = {
initAndGetDb: function () {
db = mongo.db('mongodb://localhost/dbName', {native_parser:true});
db.open(function(err) {
if (!err) {
console.log('Connected to mongodb://localhost/dbName');
}
});
db.bind('clients');
db.bind('invoices');
return(db);
},
getDb: function () {
return(db);
}
};
In my main app.js
var db = require('./db').initAndGetDb();
And in my routes.js
var db = require('../db').getDb();
Question: Is this approach a good working solution for sharing a db connection (and maybe other things in a similar fashion)? If you can see any problem with this, please let me know...
Overall I think this is fine, but you could simplify it to just:
//your db.js module
var mongo = require('mongoskin');
var db = mongo.db('mongodb://localhost/dbName', {native_parser:true});
db.bind('clients');
db.bind('invoices');
db.open(function(err) {
if (err) {
console.error('Could not connect to db', err);
return;
}
console.log('Connected to mongodb://localhost/dbName');
});
module.exports = db;
The first time your code does require("./db");, the top-level code in db.js will run and connect to the db. When other modules require it, they will get access to the db without re-running the top level code and reconnecting.
Note that to be truly ready for production you would need to enhance this with:
get DB connection details from some configuration system (env vars or a helper module)
More robust logging
Graceful handling of disconnects and reconnects while the app is running
Graceful handling of the db being down when the web app starts
retry/backoff logic around connecting/reconnecting
Decide what the webapp does when it can't reach the DB. Show a fail whale page or exit the process.
So, I was told that passing around the request and or response variable in nodeJS is "bad practice". But this means that most of your code has to be in the server.js file, making it cluttered and kind of ugly.
How can you modularize your nodejs server, passing around req/res appropriately and be able to organize your code into separate files?
For example, I would like to split my socket routing, .get and .post into different files, but still be able to use the callback parameters like so:
app.io.route("disconnect", function(req,res) { <--- these params
db.query("UPDATE player_data SET online=0 WHERE id="+mysql.escape(req.session.user));
req.io.broadcast("event", {msg:req.session.username+" has logged out!"});
app.io.broadcast("reloadXY");
});
As of right now they're all in one file and I don't like that.
I think what the person meant by 'passing around' was something like this (in plain express):
app.get('/kittens', function(req, res) {
db.doAthing(req);
updateSomethingElse(res);
upvoteThisAnswer(res);
});
That is, passing around the two variables beyond the first function. This is bad because it becomes increasingly difficult to figure out where the call actually ends. One little res.end(500) in updateSomethingElse can cause the whole house of cards to come tumbling down.
It's perfectly ok (in fact, standard to the point of being the default in express) to declare that callback elsewhere (usually the /routes directory of your project.)
// app.js
var user = require('./routes/user')
, kittens = require('./routes/kittens');
// express stuff...
app.get('/settings', user.getSettings);
app.get('/fur', kittens.shed);
Then, in routes/user.js:
exports.getSettings = function(req, res) {
// Note how we're passing around properties of req/res, not the objects themselves.
db.getUserSettings(req.user.id).then(function(settings) {
res.render('settings', settings);
});
};
This video from TJ Holowaychuk (the guy who wrote Express and a ton of other Node infrastructure that we all use) helped me take Express modularization to the next level. Basically you can make individual apps in their own folders and consume them as middleware very easily. I have managed to extend this technique to socket.io with some tricks.
http://vimeo.com/56166857
You should not pass req and res to another modules but pass callbacks from another modules to route.
It should look like.
var someModule = require("./someModule")
app.get("/someAction", someModule.handleSomeAction) ;
If You want to have post and get in another modules You should pass reference to app (from express()) once to that module and operate on that.
For example :
var express = require("express") ;
var app = express();
var get_handler = require("./get_handler ")
var post_handler = require("./post_handler ")
get_handler.init(app);
post_handler.init(app);
and in post/get_handler :
var app;
exports.init = function( eApp){
app = eApp;
// operate on app
}