Pass result of Knex.js select to ejs template - node.js

I'm currently working on a project in express and I'm using knex.js for my queries and migrations.
I haven't touched node in a while so I'm a bit rusty. Essentially I'm trying to select records from one of my tables and then call the function in one of my routes to then iterate through and output it in my ejs template.
Unit Model
'use strict'
const knex = require('knex')(require('../../knexfile'))
module.exports = function(app) {
this.getAll = function() {
knex.select('id', 'unit_prefix', 'unit_name').from('units').then(function(units) {
return units;
})
}
return this
}
Then in my routes.js file:
app.get('/dashboard', ensureAuthenticated, function(req, res) {
// console.log(req.user)
console.log(unitModel.getAll)
res.render('dashboard', { user: req.user, units: unitModel.getAll })
})
If I console.log the result of unitModel.getAll I get [Function]. I've read about how knex uses promises and is asynchronous however I still haven't managed to use other answers to solve my rather simple issue.
In my dashboard.ejs file I have this code:
<h3>Jump to unit:</h3>
<%if (units.length > 0) { %>
<% units.forEach(function(unit) { %>
<div class="dashboard-course-item" tooltip="First year unit, covers the basics of web foundations">
(<%= unit.unit_prefix %>) <%= unit.unit_name %>
</div>
<% }) %>
<% } else { %>
<strong>Currently no units have been created.</strong>
<% } %>
I currently have one record in the units table and always see the Currently no units have been created. message.
What do I need to change to return an array or object that I can iterate over in my ejs template?
Thanks in advance!

Promises return their values asynchronously in their .then callback function, if you return the promise itself it will return undefined since in that moment the promise still hasn't resolved.
To make your code work you should do something like this:
Unit Model
'use strict'
const knex = require('knex')(require('../../knexfile'))
module.exports = function(app) {
this.getAll = function(){
return new Promise(function(resolve,reject) {
knex.select('id', 'unit_prefix', 'unit_name').from('units')
.then(function(units) { resolve(units);})
.catch(function(error) {reject(error);})
})
}
return this
}
routes.js
app.get('/dashboard', ensureAuthenticated, function(req, res) {
// console.log(req.user)
unitModel.getAll()
.then(function(units){
res.render('dashboard', {
user: req.user,
units: units
})
})
})

Related

Display object from knex into ejs

I am trying to display a object in my ejs file but i'm not sure what i'm doing wrong, I keep getting Object, object. I can get it to display in the terminal but once I try and display it on the ejs page it no longer works.
all what i'm trying to do is count the number of rows and display that number on my ejs pages.
app.js
// render files
app.get('/', (req, res) => {
knex.where({ID: '1'})
.select()
.count()
.from("Table")
.then((results) =>{
res.render('Page', {Lcount: results});
})
});
I've tried to do is several ways on my ejs page but I can't seem to figure it out
ejs page
<%= Lcount %> //displays object, object
<%- Lcount %> //displays object, object
<% for (var i=0; i <Lcount.length; i++ ) { %>
<%- Lcount[i] %> // displays object, object
<% } %>
<% for (let i=0; i <Lcount.length; i++ ) { %>
<%= Lcount[i] %> //displays object object
<% } %>
for anyone having a similar issue I figured out what my the problem was with my code I needed to have a alias for my count so I can call it in my ejs. Since count() is one of the cases in knex when you are not returning a row of a table you are essentially making your own row based on your query.
app.get('/', (req, res) => {
knex("Table")
.where({ ID: '1' })
.count("ID" ,{as: 'count'}) //alias setup here
.first()
.then((results) => {
res.render('Page', {
title: 'Home',
Lcount: results
});
})
});
//ejs
<% = Lcount.count %>
Your knex query return an array of object:
[ { count: '11' } ]
As i understand you want to count the records by defined ID. So it would be more readable to write your query this way:
knex("Table")
.where({ ID: '1' })
.count()
.first() // Similar to select, but only retrieves & resolves with the first record from the query.
.then((results) => {
res.render('Page', { Lcount: results });
});
The result will be an object:
{ count: '2' }
Then you can if you want pass the result this way:
res.render('Page', {
Lcount: results.count
});
In your views/Page.ejs file:
<%= Lcount %>
In case you forgot to set the view engine:
app.set('view engine', 'ejs');
I don't understand how the result could be
{ ": 26 }
It seems to be malformed. To find where it goes wrong, what you can do, is to try this simple query directly from you database and paste the result:
SELECT count(ID) FROM Table WHERE ID = 1;

Get a database value using mongoose and displaying in the same page (ExpressJS and MongoDB)

That is my first project in web development in general and I am using ExpressJS and MongoDB. I basically want to click a button in my view page and then get a specific data in the database (mongodb) to show the content just above the button element. That is what I have so far:
My Schema (I have a different schema for users, but that is the one that I want to get the data from).
const mongoose = require('mongoose');
// Redacao Schema
var RedacaoSchema = mongoose.Schema({
testing1: {
type: String
}
});
var Redacao = module.exports = mongoose.model('Redacao', RedacaoSchema);
Here I want to click in a button, get a specific data from the database and show in the same page above the button. I am using handlebars as my view engine. My view:
<div id="target">
</div>
<input id="receberRedacao" type="button" value="User data">
<script>
$(document).ready(function(){
$('#receberRedacao').click(function (e) {
e.preventDefault();
$.ajax({
url: "/users/usuario/redacaoteste",
type: "get",
});
console.log(texto1);
$("<div id='redacao-usuario'>A redação do usuário está aqui. >>> {{texto1}} </div>").appendTo('#target');
});
});
</script>
My router:
var express = require('express');
var router = express.Router();
var Redacao = require('../models/redacao');
router.get('/usuario/redacaoteste', function(req, res) {
var texto1 = Redacao.findOne({});
console.log('>>>', texto1); //testing the variable I get something crazy
res.render('usuario', {texto1});
});
module.exports = router;
You should use a callback as findOne is asynchronous:
router.get('/usuario/redacaoteste', function(req, res) {
Redacao.findOne({}, function(err, doc) {
if (err) {
// Handle error here
}
console.log('>>>', doc);
res.render('usuario', doc);
});
});
I find the answers for my problematic code. I'll post the answers here as they may help others.
Server side:
1º I should have a promise to handle the errors when finding a variable in the database.
2º Can't use res.render. It should be res.json to pass the variable, otherwise it will return the entire html code.
router.get('/usuario/receber', function(req, res) {
Redacao
.findOne({})
.then(doc => {console.log(doc), res.json(doc)})
.catch(err => {
console.log(err);
res.status(500).send({ message: err });
});
});
Client side: I missed the success function in the Ajax request.
function successCallback(responseObj){
console.log(responseObj);
};
$(document).ready(function(){
$('#receberRedacao').click(function (e) {
e.preventDefault();
$.ajax({
url: "/users/usuario/receber",
type: "get",
success: function(response){
successCallback(response);
}
});
});
});

EJS Helper function moongose

recently I faced the problem that the result from database is not as not be able to display on the page. What am I doing wrong ?
This is the function code which is located in index.js
res.locals.get_user_name = function () {
User.findOne({_id: 2}).exec().then(function (user) {
return user.name;
});
};
And this is a code template EJS
<div class="name"><% get_user_name() %></div>

Trying to get data to display in a table

I'm working on my first node project using express and sequelize, and I'm not understanding how the page rendering works
I have the following function in my one of my models(sequelize):
getGreetings: function (req, res) {
Greeting.findAll({
}).then(function (data) {
console.log('Returned data for greetings: ' + data);
res.send({greetings:data});
})
}
Here is my route:
var Greeting = require('../models/greetings');
router.get('/', function(req, res) {
res.render('index', function(){
Greeting.getGreetings(req, res);
});
});
and my ejs table I want to display the data in:
<tbody>
<% for(var i=0; i < greetings.length; i++) { %>
<tr>
<td><%= greetings[i].name %></td>
<td><%= greetings[i].message %></td>
</tr>
<% } %>
</tbody>
This isn't displaying any of the html, but rather echoing out the json data. Can someone help explain why my html table isn't being populated?
but rather echoing out the json data.
This is because getGreetings() is always setting that as the response, by using res.send():
res.send({greetings:data});
To provide greetings to your view, you'll have to instead provide the data within the locals given to res.render():
res.render('index', { greetings: data });
The two methods don't cooperate with each other. Each is defined to end the response itself, so you'll only be able to use one per response.
If you revise getGreetings to return the promise created by .findAll():
getGreetings: function (req) {
return Greeting.findAll({
// ...
});
}
Then, the route handler can bind to it and decide how to make use of the result itself – whether it should use res.send() or res.render():
var Greeting = require('../models/greetings');
router.get('/', function(req, res) {
Greeting.getGreetings(req).then(function (greetings) {
res.render('index', { greetings: greetings });
});
});

Need help using EJS

I am exploring the use of the EJS templating system and am unsure of how to use it to get SQL data to be available to be rendered in a view.
In my app.js I have something like this:
conn.query("select name,age from people", function(err, people, moreResultSets) {
for (var i=0;i<people.length;i++){
console.log(people[i].NAME, "\t\t", people[i].AGE);
}
conn.close(function(){
console.log("Connection Closed");
});
});
And I have the following code to route the proper view:
app.get('/test1', function(req, res) {
res.render('pages/test1');
})
My confusion lies in making the people data available from the query
statement to be rendered in the view. All of the examples I have seen
have the variables defined locally inside the app.get code block and I
am unclear how to jump from that to my situation.
Thank you for any assistance you can provide!
-Andy
Render after you have the data.
app.get('/test1', function (req, res) {
conn.query("select name,age from people", function (err, people, moreResultSets) {
res.render('pages/test1', {
people: people
});
conn.close(function () {
console.log('Connection Closed');
});
});
});
HTML
<% if (people) { %>
<% for (var i = 0; i < people.length; i++) { %>
<div><%= people[i].name %></div>
<% } %>
<% } else { %>
<div>No people found</div>
<% } %>

Resources