Cannot create property '_locals' on string - node.js

Hello im trying to select from my databas however it [Object,object]. Then I searched around and got the answer to stringify, however now I got a new issues saying "Cannot create property '_locals' on string " anybody knows how to solve it?
app.get('/behandlare', function(req, res){
pool.connect(function(err, table, done){
if(err) {
return console.error('error fetching staff from table', err);
}
table.query('SELECT * FROM public.staff', function(err, result){
if(err){
return console.error('error runnig query', err);
}
res.render('behandlare.ejs', JSON.stringify({staff: result.rows}));
done();
});
});
});
.ejs
<div class = "ruta">
<img src="img/spakvinna.jpg" alt="" style="width:400px;height:250px;"><%= name %>
<p class="sida2"></p>
</div>

OK, so i'm assuming that res.render('behandlare.ejs', JSON.stringify({staff: result.rows})); actually requires an object in express and not a string... so instead of doing stringify just pass the object. Ummm... I assume that you might be using it in a wrong way in the template you are using or something of that sort but if it gets you back to the previous error maybe that was the real problem and you need to see how to solve that.

Inside res.render has to be an object literal
// option 1
const myObj = {
obj: req.body,
hats:["white","grey","black"]
};
res.render( 'success', { myObj } )
// or option 2
res.render( 'success', { myObj: req.body } )
It have to be literally an object
Object Definition
How-to define (and create) a JavaScript object with an object literal
const myObj = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"blue"
};

Related

node js SQL Insert Query with Constructor / JSON text as values parameter

First real app and I'm stuck trying to insert a new row into SQL.
//This is the API endpoint
Sponsor.create = (newSponsor, result)=> {
var sqlStmt = 'insert into sponsors (SponsorName, SponsorState, SponsorDesc, pnfpExperience, Status) values ?'
sql.query(sqlStmt, [newSponsor], (err, res)=> {
if(err) {
console.log(" error: ", err);
result(null, err);
}
else{
console.log(res);
result(null, res);
}
});
};
request.body returns the JSON text but not an array of values that can be used in the query. I keep getting a COUNT error or syntax error. I've tried JSON.parse but I get an undefined error. I know there has to be a simple way to convert the JSON text to the right format but I don't know what I'm missing. The "findAll" and "findById" routes work and I can insert static values. I've also tried "newSponsor" with and without brackets. I'll refine the connection method in time but I'm just trying to understand why this doesn't work. Any help is greatly appreciated.
// Controller.js for Reference
exports.create = function(req, res) {
const new_sponsor = new Sponsor(req.body);
//handles null error
if(req.body.constructor === Object && Object.keys(req.body).length === 0){
res.status(400).send({ error:true, message: 'Please provide all required field' });
}else{
Sponsor.create(new_sponsor, function(err, sponsor) {
if (err)
res.send(err);
res.json({error:false,message:"Sponsor added successfully!",data:sponsor});
});
}
};

Retrieving data from MongoDB causes "Cannot read property 'firstname' of null" error"

I have been trying to return some users info and to display them trough HTML. But I am getting the error:
"Cannot read property 'firstname' of null" error"
To store data I am using MongoDB, for the backend service Express and Node.js and for the frontend Angular.
To communicate between back and frontend I delegated that to HttpClient. Connection with Mongo works fine since my console receiving all data but when it comes to the frontend side it's giving me this issue.
routes-index.js class method for connection with MongoDB
router.get('/tasks', async (req, res) => {
let MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
res.json([
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('angular-auth');
dbo.collection('users').find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
//db.close;
});
})
])
});
tasks.service.ts class method for returning data to frontend
getTasks() {
return this.httpClient.get<any>(this.URL + '/tasks');
}
private-tasks.component.ts class ngOnInit() method which supposes to get and to subscribe data
ngOnInit(): void {
this.tasksService.getTasks()
.subscribe(
res => {
console.log(res); //<===== this line is returning null value!
this.tasks = res;
},
err => console.log(err)
);
}
private-tasks.component.html class
<ul class="list-group">
<li class="list-group-item" *ngFor='let task of tasks'>
{{task.firstname}}
</li>
</ul>
console.log(res); gives null value, but within if/else statement it's actually not null... How I am sure that is not... coz the same method is giving me output in the console. I have tried also to add ? to {{task?.firstname}} in that way I am not getting any error but still console.log(res); gives null value.
Is there anything that you can suggest how to approach this problem?
The culprit is the res.json call on the back-end side. The front-end side of the code seems good. The argument of the function call is supposed to be an object that you return from the server to the client, but what you'\re giving it instead if whatever MongoClient.connect returns -- which is probably nothing (I've never used it so I can't be sure).
The place where you call console.log is inside the innermost callback function. At the moment this piece of code runs, the database has responded and the response is ready to be sent to the client. But you attempt to send the data to the client before this callback is run.
So the correct approach is to place res.json inside the innermost callback, which runs when the data is available.
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('angular-auth');
dbo.collection('users').find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
res.json(result); // <-- res.json goes inside, after data is available
});
});
This sounds like an Async issue, here is what you can try in your service.ts file:
You will need to have some sort of mongo model to hold the data. For example:
private tasks:TaskModel[] = []
In addition to a model, you will want to have a subject which you will need to import from rxjs.
import {Subject} from 'rxjs';
and
private taskUpdated = new Subject<taskModel>[](); //create a new subject of type taskModel that you will add to
The last bit to update in your service.ts file would be this:
getTasks(){
this.httpClient.get<any>(this.URL + '/tasks')
.subscribe((taskData)=> {
this.taskNotes = taskData;
this.taskUpdated.next([...this.taskNotes])//adding in taskNotes
})
getTasksUpdatedAsListener(){
return this.taskUpdated.asObservable();//observable that you will subscribe to in component.ts
}
Then in your component.ts file you will create another subscription object and change your code to this:
//subscription that needs to be created
private sub:Subscription;
ngOnInit(): void {
this.tasksService.getTasks()//this needs to go first. It will get data in the service file
this.sub = this.taskService.getTasksUpdatedAsListener()
.subscribe((data TaskModel[])=> {
console.log(data);//you should see the data come in as json
})
}
Let me know how it goes!
I had the same problem and deleted the sessions in mongodb, the problem was solved.

ApostropheCMS Contact us form with attachment

I am new to Apostrophe and trying to create a contact us form with file attachment in Apostrophe by following the tutorial.
https://apostrophecms.org/docs/tutorials/intermediate/forms.html
I have also created the attachment field in my index.js and it works fine from the admin panel.
Now, I am trying to create my own html for the form with file submission.
// in lib/modules/contact-form-widgets/public/js/always.js
apos.define('contact-form-widgets', {
extend: 'apostrophe-widgets',
construct: function(self, options) {
self.play = function($widget, data, options) {
var $form = $widget.find('[data-contact-form]');
var schema = self.options.submitSchema;
var piece = _.cloneDeep(self.options.piece);
return apos.schemas.populate($form, self.schema, self.piece, function(err) {
if (err) {
alert('A problem occurred setting up the contact form.');
return;
}
enableSubmit();
});
function enableSubmit() {
$form.on('submit', function() {
submit();
//I can access file here
// console.log($form.find('file'))
return false;
});
}
function submit() {
return async.series([
convert,
submitToServer
], function(err) {
if (err) {
alert('Something was not right. Please review your submission.');
} else {
// Replace the form with its formerly hidden thank you message
$form.replaceWith($form.find('[data-thank-you]'));
}
});
function convert(callback) {
return apos.schemas.convert($form, schema, piece, callback);
}
function submitToServer(callback) {
return self.api('submit', piece, function(data) {
alert("I AM AT SUBMIT API ")
if (data.status === 'ok') {
// All is well
return callback(null);
}
// API-level error
return callback('error');
}, function(err) {
// Transport-level error
alert("I AM HERE AT API ERROR")
return callback(err);
});
}
}
};
}
});
//and my widget.html is
<div class="form-group">
<input name="custom-file" type="file">
</div>
When I run this I get following errors
user.js:310 Uncaught TypeError: Cannot read property 'serialize' of undefined
at Object.self.getArea (user.js:310)
at Object.self.getSingleton (user.js:303)
at Object.convert (user.js:686)
at user.js:164
at async.js:181
at iterate (async.js:262)
at async.js:274
at async.js:44
at setImmediate.js:27
at runIfPresent (setImmediate.js:46)
My question is, how do I handle file submission? Is there any better approach for this?
This is much easier to do using the apostrophe-pieces-submit-widgets module, which allows you to define a schema for what the user can submit. You can include a field of type attachment in that, and this is demonstrated in the README.

Mongoose - function inside .find method does not pass result

How do I pass the result of the function successfully into .find method ? I want the argument passed via body-parser to be used as value for the key 'name' if user submitted a non-empty string. If user submitted an empty string, then empty object should be passed into .find method.
Function console.log works. If I submit an empty string then 'empty querydb' is printed to the console. Likewise, if I submit any other string then it gets printed out to the console correctly.
How can I pass the req.body.querydb as a value to 'name' key ?
HTML
<form method="POST" action="form_query">
<input type="textarea" name="querydb">
<br><br>
<button> Query </button>
</form>
.JS
router.post('/form_query', function(req,res) {
someModel.find(function(err,results){
if(!req.body.querydb){
console.log("empty querydb")
return {}
} else {
console.log(req.body.querydb)
return {name:req.body.querydb}
}
}).exec(function(err, result) {
if (err) {
send(err)
} else {
console.log('omg')
}
Much thanks !
In mongoose you have two possibilities to make a find request
the find(query, callback) function
the query builder
I recommand you to use the find() function. In your case, your code is like more this :
router.post('/form_query', function(req,res, next) {
someModel.find({
name : req.body.querydb
}, function (err, users) {
if (err) {
// request has an error like connection problem
res({ error : err });
return;
}
// request works correctly, you can send the users array for example
res(users);
});
});
The find function works like the mongodb pure find() function and, for me, it's the best way to make your requests.
EDIT :
It is advisable to control the incoming variables in the best way to perform this find.
For example, You can make this :
let findQuery = {};
if (req.body.querydb) {
findQuery.name = req.body.querydb
}
someModel.find(findQuery, function (err, users) {
// ...
});
I am not really sure what you are looking for but trying to understand as much as possible i am giving some code. This way you pass req.body.querydb as a value to 'name' key.
router.post('/form_query', function(req,res) {
someModel.find({name:req.body.querydb},function(err,results){
if(!req.body.querydb){
console.log("empty querydb")
return {}
} else {
console.log(req.body.querydb)
return {name:req.body.querydb}
}
}).exec(function(err, result) {
if (err) {
send(err)
} else {
console.log('omg')
}
From what I can tell you are looking to pass a value from the api into a mongo query.
It might make sense to define the query outside of the actual call and then build it as needed or to ensure that a value is passed before getting to the query.
For example:
router.post('/form_query', function(req,res) {
if(!req.body.querydb) {
return res.status(404).send("empty querydb");
}
// validate querydb param
someModel.find({ name: req.body.querydb }, function(err,results){
if(!req.body.querydb){
console.log("empty querydb")
res.send
} else {
console.log(req.body.querydb)
return res.status(200).send(results);
}
})
});
If you are using mongoose then the callback will be called after execution, and the query is the first param passed into the .find function.

Pull mongo data to ejs template

I have the following basic document in mongo:
connecting to: test
> db.car.find();
{ "_id" : ObjectId("5657c6acf4175001ccfd0ea8"), "make" : "VW" }
I am using express, mongodb native client (not mongoose) and ejs.
collection.find().toArray(function (err, result) {
if (err) {
console.log(err);
} else if (result.length) {
console.log('Found:', result);
mk = result;
console.log('mk = ', mk);
} else {
console.log('No document(s) found with defined "find" criteria!');
}
//Close connection
db.close();
});
}
});
Here is the render code:
// index page
app.get('/', function(req, res) {
res.render('pages/index', { make: result });
});
And i want to pass the data make: VW into my index.ejs file:
<h2>Cars:</h2>
<h3>My favorite make is <%= make %>
This should be real simple and straightforward but i just don't understand how to pass the "mk" variable (which i can console.log to the screen) to be rendered by the ejs view?
You should use the find method inside the route (or with a callback) to get the result and render it:
app.get('/', function(req, res) {
collection.find().toArray(function(err, result) {
if(err) {
console.log(err);
res.status('400').send({error: err});
} else if(result.length) {
console.log('Found:', result);
mk = result;
console.log('mk = ', mk);
res.render('pages/index', {make: mk});
} else {
console.log('No document(s) found with defined "find" criteria!');
res.status('400').send({error: 'No document(s) found'});
}
//Close connection
db.close();
});
});
Very simple, your are outputting an array of JSON objects
Here is one way to visualise it:
[{a:b},{a:b},{a:b},{a:b}];
If you want the first result it would be array[0].a
so you simply need to call it this way:
<%= make[0].(your database key here) =>
//example
<%= make[0].name =>
A more sensible way to get this done would be to iterate through the array and output only the result you want on the server side. If you send all your data to your client you might have security issues depending on what you send.
It should be simple, but you are defining mk just like this: mk = result So because you want to pass a variable to an ejs file you need
"var mk = result"
Have a good day, Ben.

Resources