Profile.js code goes as below
'use strict';
var service = require('../services/Profile');
class Profile {
updateProfile(req, resp) {
this.updateUserDetails(req, resp);
}
updateUserDetails(req, resp){
var admin = req.body;
resp.json({"success":true,"message":"User Updated"});
}
}
module.exports = new Profile();
server.js code goes as below
...... Some code -------
var profile = require("./controllers/Profile")
app.put("/api/profile", auth, profile.updateProfile);
...... Some code -------
When I make the call <>/api/profile I am getting error
TypeError: Cannot read property 'updateUserDetails' of undefined ,
(at line number of code this.updateUserDetails(req, resp);)
Since there is some common logic so I need to move to some function and want to call in different place, but I am getting this error. I am new to node js looking for help.
This is a classic misunderstanding of how this works in javascript. I'd suggest you search stackoverflow for the phrase "how this works in javascript".
As for your code, you either need to do this:
app.put("/api/profile", auth, function (req,res) {
profile.updateProfile(req,res)
});
or this:
app.put("/api/profile", auth, profile.updateProfile.bind(profile));
I moved the function out of class and using it, it worked
'use strict';
var service = require('../services/Profile');
class Profile {
updateProfile(req, resp) {
updateUserDetails(req, resp);
}
}
function updateUserDetails(req, resp){
var admin = req.body;
resp.json({"success":true,"message":"User Updated"});
}
module.exports = new Profile();
change your code to:
var prof = new Profile();
module.exports = prof;
and then use it in the other method like this:
class Profile {
updateProfile(req, resp) {
prof.updateUserDetails(req, resp);
}
this should work just fine.
Related
I'm trying to make it so that I can pass my trends variable from its function into a renderer for my Pug template, and I can't seem to do it.
var express = require('express');
var router = express.Router();
var googleTrends = require('google-trends-api');
var auth = require('http-auth');
var ustrends;
var uktrends;
const Console = require('console').Console;
var basic = auth.basic({
realm: "Web."
}, function (username, password, callback) { // Custom authentication method.
callback(username === "user" && password === "pass");
}
);
var find = ',';
var regex = new RegExp(find, 'g');
googleTrends.hotTrends('US').then(function(trends){
ustrends = trends
});
googleTrends.hotTrends('EU').then(function(trends1) {
uktrends = trends1
});
console.log(ustrends);
/* GET home page. */
router.get('/', auth.connect(basic), function(req, res, next) {
res.render('index', {trends: ustrends.toString().replace(regex, ", "), trends1: uktrends.toString().replace(regex, ", "), title: 'Trends in the U.S & U.K'});
});
module.exports = router;
As you can see, I'm trying to pass the "ustrends" and "uktrends" variables into the renderer. Any help is appreciated.
Remember that hotTrends will return a promise, as it's getting results from Google's API. Since the renderer is outside of the callbacks wherein ustrends and uktrends are set to values, there's no guarantee these values will be set prior to the renderer being called.
You could use several nested callbacks, but that would lead to some code pushed pretty far to the right; I recommend the async library, which has a function called series that allows you to pass in 1) an array of functions to be executed in order and 2) a callback that will be executed after the functions have completed that takes an error if there was one and the result of the functions as an argument. In the snippet below, the trends API returns results prior to the renderer being called:
async.series([
function(cb) {
googleTrends.hotTrends('US').then(function(trends){
ustrends = trends;
cb();
})
},
function(cb) {
googleTrends.hotTrends('EU').then(function(trends1) {
uktrends = trends1;
cb();
});
}
], function(err, results) {
/* handle errors, do rendering stuff */
})
Let's say I have a module that exports like this:
module.exports = mymodule;
Then in my test file, I require the module and stub it.
var mymodule = require('./mymodule');
describe('Job gets sports data from API', function(){
context('When there is a GET request', function(){
it('will call callback after getting response', sinon.test(function(done){
var getRequest = sinon.stub(mymodule, 'getSports');
getRequest.yields();
var callback = sinon.spy();
mymodule.getSports(callback);
sinon.assert.calledOnce(callback);
done();
}));
});
});
That works and the test passes! But everything breaks down if I need to export more than one object. See below:
module.exports = {
api: getSports,
other: other
};
Then I try to adjust my test code:
var mymodule = require('./mymodule');
describe('Job gets sports data from API', function(){
context('When there is a GET request', function(){
it('will call callback after getting response', sinon.test(function(done){
var getRequest = sinon.stub(mymodule.api, 'getSports');
getRequest.yields();
var callback = sinon.spy();
mymodule.api.getSports(callback);
sinon.assert.calledOnce(callback);
done();
}));
});
});
In this case, my test craps out. How can I change my stub code to work? Thanks!
Based on this
module.exports = {
api: getSports,
other: other
};
it looks like mymodule.api doesn't itself have a getSports method. Rather, mymodyle.api is a reference to a getSports function insider your module.
Instead of stubbing getSports you would need to stub api:
var getRequest = sinon.stub(mymodule, 'api');
However, given how you're trying to stub getSports, you might instead want to update how you are exporting the function instead of how you are stubbing it.
I am trying to pass data to Mongodb using Websocket and total.js.
In my homepage.html I can get the user input and connect to the server via websocket after clicking the save button.
In default.js is my server side code. At this point the app hat got the user input and connected to the server correctly, but how can I save data to mongodb now?
This is my homepage.html
<br />
<div>
<input type="text" name="message" placeholder="Service" maxlength="200" style="width:500px" />
<button name="send" >Save</div>
</div>
<br />
<script type="text/javascript">
var socket = null;
$(document).ready(function() {
connect();
$('button').bind('click', function() {
if (this.name === 'send') {
console.log(send());
return;
}
});
});
function connect() {
if (socket !== null)
return;
socket = new WebSocket('ws://127.0.0.1:8000/');
socket.onopen = function() {
console.log('open');
};
socket.onmessage = function(e) {
var el = $('#output');
var m = JSON.parse(decodeURIComponent(e.data)).message;
el.val(m + '\n' + el.val());
};
socket.onclose = function(e) {
// e.reason ==> total.js client.close('reason message');
console.log('close');
};
}
function send() {
var el = $('input[name="message"]');
var msg = el.val();
if (socket !== null && msg.length > 0)
socket.send(encodeURIComponent(JSON.stringify({ message: msg })));
el.val('');
return msg;
}
This is my default.js
exports.install = function(framework) {
framework.route('/', view_homepage);
framework.route('/usage/', view_usage);
framework.websocket('/', socket_homepage, ['json']);
};
function view_usage() {
var self = this;
self.plain(self.framework.usage(true));
}
function view_homepage() {
var self = this;
self.view('homepage');
}
function socket_homepage() {
var controller = this;
controller.on('open', function(client) {
console.log('Connect');
});
controller.on('message', function(client, message) {
console.log(message);
/*
var self = this;
var message = MODEL('message').schema;
var model = self.body;
var message = new message({ message: model.message }).save(function(err) {
if (err)
self.throw500(err);
// Read all messages
message.find(self.callback());
});
*/
});
controller.on('error', function(error, client) {
framework.error(error, 'websocket', controller.uri);
});
}
Any help Please!!!
This is complete project
---Update---
In this function i use to save data to MongoDB
but it didn't give any error.also Didnt save the data to database.i not sure my code is write or wrong
controller.on('message', function(client, message) {
console.log(message);
/*
var self = this;
var message = MODEL('message').schema;
var model = self.body;
var message = new message({ message: model.message }).save(function(err) {
if (err)
self.throw500(err);
// Read all messages
message.find(self.callback());
});
*/
});
This my mongoose.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://totaldemo:123456#ds029979.mongolab.com:29979/totaldemo');
global.mongoose = mongoose;
This is my user.js
var userSchema = mongoose.Schema({ user: String})
exports.schema = mongoose.model('user', userSchema,'user');
exports.name = 'user';
I don't know totaljs framework at all, but i see some issues already with plain javascript.
First of all, i suggest You set up Your model like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
user: String
});
module.exports = mongoose.model('User', userSchema);
and then in controller, when You import:
var User = require('path/to/user/file')
You can use it like this straight away:
User.find()
Also - i totally dont get what are You doing later.
You defined user model and exported NOTHING MORE than a STRING. Only tthing it will do is, that when You import that user to variable User, the User.name will === to 'user' string. so in Your example it would be:
var User = require('path/to/user/model/file')
console.log(User.name) // prints 'user'
and nothing more! There are no models attached to that export. Maybe its how totaljs works, but i VERY doubt it.
Later on - You try to ... use message model. Where it comes from? You defined user model, not message model.
Another thing - as i stated - i dont know totaljs, but I doubt it ask YOu to define var model, and then never use variable model.
I strongly suggest using plain node with mongoose first, then try to integrate it with any fullstack.
For sure its not a solution, but maybe it points out some problems in Your code and will help.
EDIT:
I looked quickly in totaljs, and it looks that You really should export string (which is little weird and doing magic stuff:) ), but its NOT mongoose, and i guess will ONLY work with native totaljs model solution. You cant use mongoose and totaljs like that. I dont know how much not using native totaljs models system ruins framework other options, but its probably safer to use native one.
Honestly, i dont have time to look deeper into docs, but google says nothing about sql or even mongo inside of totaljs docs... so, You have to figure it out :)
EDIT2 i found https://github.com/totaljs/examples/tree/master/mongoose and it looks weird... check if that example works (looks like You seen it, Your code is similar :)). check if You're mongod is working, check if You can conenct from plain node...
Honestly sorry, i surrender. Totaljs has to much magic and abstraction for me to help You out with this :(. Hope You will find Your answer.
I'd like to create a model to handle everything related to users, starting with a findOne() function.
app.js:
var u = new User(client);
u.findOne(function(error, user) {
console.log(error, user);
});
models/User.js:
var User = function (client) {
this.client = client
};
User.prototype.findOne = function (id, callback) {
client.connect();
client.get('testkey', function(error, result) {
var test = "hello#world.com";
callback(null, test);
client.close();
});
};
module.exports = User;
node.js complains findOne() would be undefined.
What's the correct way of creating such models and providing them with objects, like database pools etc.?
Your code contains various errors:
You do not use new when creating the instance
You mixed a function with the object literal syntax:
var User = function (client) {
client: client
};
You want this.client = client; instead. Right now the function body does nothing as it just defines a label called client does nothing with the variable client.
I would suggest you to search for an existing ORM for node.js instead of trying to write one on your own.
I have the following code in server/statusboard.js;
var require = __meteor_bootstrap__.require,
request = require("request")
function getServices(services) {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}
Meteor.startup(function () {
var services = [];
getServices(services);
console.log(services);
});
Basically, it's pulling some data from a JSON feed and trying to push it into a collection.
When I start up Meteor I get the following exception;
app/packages/livedata/livedata_server.js:781
throw exception;
^
Error: Meteor code must always run within a Fiber
at [object Object].withValue (app/packages/meteor/dynamics_nodejs.js:22:15)
at [object Object].apply (app/packages/livedata/livedata_server.js:767:45)
at [object Object].insert (app/packages/mongo-livedata/collection.js:199:21)
at app/server/statusboard.js:15:16
at Array.forEach (native)
at Function.<anonymous> (app/packages/underscore/underscore.js:76:11)
at Request._callback (app/server/statusboard.js:9:7)
at Request.callback (/usr/local/meteor/lib/node_modules/request/main.js:108:22)
at Request.<anonymous> (/usr/local/meteor/lib/node_modules/request/main.js:468:18)
at Request.emit (events.js:67:17)
Exited with code: 1
I'm not too sure what that error means. Does anyone have any ideas, or can suggest a different approach?
Just wrapping your function in a Fiber might not be enough and can lead to unexpected behavior.
The reason is, along with Fiber, Meteor requires a set of variables attached to a fiber. Meteor uses data attached to a fiber as a dynamic scope and the easiest way to use it with 3rd party api is to use Meteor.bindEnvironment.
T.post('someurl', Meteor.bindEnvironment(function (err, res) {
// do stuff
// can access Meteor.userId
// still have MongoDB write fence
}, function () { console.log('Failed to bind environment'); }));
Watch these videos on evented mind if you want to know more:
https://www.eventedmind.com/posts/meteor-dynamic-scoping-with-environment-variables
https://www.eventedmind.com/posts/meteor-what-is-meteor-bindenvironment
As mentioned above it is because your executing code within a callback.
Any code you're running on the server-side needs to be contained within a Fiber.
Try changing your getServices function to look like this:
function getServices(services) {
Fiber(function() {
services = [];
request('http://some-server/vshell/index.php?type=services&mode=json', function (error, response, body) {
var resJSON = JSON.parse(body);
_.each(resJSON, function(data) {
var host = data["host_name"];
var service = data["service_description"];
var hardState = data["last_hard_state"];
var currState = data["current_state"];
services+={host: host, service: service, hardState: hardState, currState: currState};
Services.insert({host: host, service: service, hardState: hardState, currState: currState});
});
});
}).run();
}
I just ran into a similar problem and this worked for me. What I have to say though is that I am very new to this and I do not know if this is how this should be done.
You probably could get away with only wrapping your insert statement in the Fiber, but I am not positive.
Based on my tests you have to wrap the insert in code I tested that is similar to the above example.
For example, I did this and it still failed with Fibers error.
function insertPost(args) {
if(args) {
Fiber(function() {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}).run();
}
}
I did this and it ran fine with no errors.
function insertPost(args) {
if(args) {
post_text = args.text.slice(0,140);
T.post('statuses/update', { status: post_text },
function(err, reply) {
if(reply){
// TODO remove console output
console.log('reply: ' + JSON.stringify(reply,0,4));
console.log('incoming twitter string: ' + reply.id_str);
// TODO insert record
var ts = Date.now();
Fiber(function() {
id = Posts.insert({
post: post_text,
twitter_id_str: reply.id_str,
created: ts
});
}).run();
}else {
console.log('error: ' + JSON.stringify(err,0,4));
// TODO maybe store locally even though it failed on twitter
// and run service in background to push them later?
}
}
);
}
}
I thought this might help others encountering this issue. I have not yet tested calling the asynchy type of external service after internal code and wrapping that in a Fiber. That might be worth testing as well. In my case I needed to know the remote action happened before I do my local action.
Hope this contributes to this question thread.