NodeJS - AngularJS Send JSON object and render templat at same time? - javascript

I have some problems with my api.
I use NodeJS with ExpressJS Routing and AngularJS.
What I want to do is to render a template (ejs) and at the same time send a json object.
In my routes folder I have the index.js file with this (a little part) :
router.get('/data', function(req, res, next){
Planning.getPlanningM(function(resultat){
res.json(resultat);
res.render('index');
});
});
About the variable resultat I'm sure that it contains that I want. But I can't do the res.json and the res.render. Because of the two invoke of send function.
And in my angular I have this in a function :
var resultat = []
$http.get('/data')
.success(function(res){
angular.extend(resultat, res.data);
})
.error(function(res){
console.log('err');
})
return resultat;
The goal is to render my index.ejs and to show my planning in this page. But I find no solution to do this.
This is my first ask on stackoverflow, english is not my native language. Please don't be rude with me :)

I'm not familiar with EJS, I use handlebars, but you should be able to pass data in the render function like so-
...
res.render("index", { data:resultat });
...
Then access it in the template in whatever format EJS uses. For hbs it would look something like
...
<div>My data looks like this: {{data}}</div>
...
Again, EJS is sure to do it differently, refer to the doc to ensure you have the correct format.

Thanks for your answer MPawlak !It helped me !
That I want is to send the data with the render like you do yes.
But I want to grab/take this data in my angular Factory (my factory fills the controller, this part works) that I show before :
var resultat = []
$http.get('/data')
.success(function(res){
angular.extend(resultat, res.data);
})
.error(function(res){
console.log('err');
})
return resultat;
With your method, I can take this data into my view directly your right and it's works ! Thanks !
<pre> <%= data %> </pre>
So I was thinking about a dirty temporaly solution to do this:
<textarea ng-model="planning"> <%= data %> </textarea>
But when I want to show this planning it don't work and stay empty... I don't understand why.
But to get a good and clean solution I think this is not a good idea, so my ask is the same... how to take this data in my angular factory directly ?

Related

How to submit data then post on another page mongoDB/Node.js

I am needing to have 1 page of a website submit data to MongoDB then pull that same data and display it on a different page. I am using node.js, express, Mongoose, and MongoDB.
Currently, I have it so It gets submitted properly to the database, and I can see it with the correct layout, But I cannot seem to get it posted on the page.
How exactly do I go about doing this?
Can someone give a example of code of this?
I am really new to this stuff and still learning.
Thanks!
In the route of the page you want to load, use the Mongoose .find()
method.
You can use {} in the find() method to return all the data, or access
individual data based on the object key find({id:'value'}). Then when you
render the page, just pass in an object to the render, where the key is
what you access in the url page, in my example you would use
(mongs) to access the values within the url page (.ejs, etc). So in
your route definition file:
app.get('/', (req, res) => {
MongModel.find({}, (err, foundMongModel) => {
err ? console.log(err) : res.render('url/route', { mongs: foundMongModel });
});
});
Then if you're using .ejs file, you would need to use <%= %> to access
individual data, and <% %> to use a loop or something.
and use the mongs value. So if you imported all the data from the
database, you could loop through it using
<% mongs.forEach(mong =>{ %>
<div>mong.key<div>
<% }) %>
You can access the keys for each database object like above using
mong.key

Can't Render EJS Template on Client

I'm coding an application on express, and I'm using ejs as a view/template engine.
At path /artists, I'm rendering the view artists.ejs which has artists covers. When clicking on a cover, I want an AJAX call to retrieve the corresponding data, place it in my template/view for artist artist.ejs and display this template in my HTML under the cover.
I've seen this related question but it has not solved my use case.
Everything seems clear, but I can't render the data with the template. I would like to compile the template server-side, send it to the client ready to use, and then fill it in when needed with the data received from the AJAX call.
What I've done:
When calling /artists, compile on server-side using ejs.compile(str, opt):
router.get('/artists', function(req, res) {
// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) { // Convert template file to string
artist_template = ejs.compile(template); // Compile template
res.render('artists.ejs', {template: artist_template}); // render page with compiled template
});
I took care of converting the file into String, as ejs compiler only works with String (compared to Jade .compileFile)
Then on client-side, I grab the function:
<script>
var template = <%= template %>
</script>
Then on another script, I retrieve the data with an AJAX call:
$.get('/artists/'+artist_name, function(data) {
var html = template({artist: data});
$('#artist-page').html(html);
}
But when I make the call, I receive:
Uncaught ReferenceError: fn is not defined
When I call the template, fn, I receive:
Uncaught ReferenceError: opts is not defined.
Is the function fn hard-coded? I've read the EJS and Jade documentation but there was little relevant information in regards to my issue.
Do I perhaps need the template on client-side also?
I eventually found a workaround to my question, and I understood with your answer that you could proceed in 2 different ways:
1) What I did: read and save template as a string, then render it client-side with ejs Runtime script.
// In controller.js
var templates = {};
templates.template1 = fs.readFileSync(filePath1, 'utf-8'); // Read template as a string
templates.template2 = fs.readFileSync(filePath2, 'utf-8');
...
res.render('app.ejs', {templates: templates}); // Send templates in view
// In view app.ejs
<script type="text/javascript">
var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of strings)
</script>
<script type="text/javascript" src="/JS/ejs.min.js"></script> <!-- Load ejs RunTime -->
// In site.js - javascript client/public file
$.get('/artists', function(data) {
var html = ejs.render(templates.template1, data); // Render ejs client side with EJS script (template1 corresponds to the artists template)
$('#artists-wrapper').html(html); // Sets HTML
});
Thus, I send all my templates on first page load, and then I render the requested page on the client side. The interest, according to what I've read, is that you only send JSON object (your data) through AJAX calls, and not the entire page, making your request light. Only the first load is heavy with all your templates.
2) What I would like to do according to #RyanZim answer: compiling templates server side into functions, send them, and then call them on the client side : template(data). If I understood well, there is no need of EJS client library in this case, and my templates are no longer strings but functions:
// In controller.js
var templates = {};
templates.template1 = ejs.compile(fs.readFileSync(filePath1, 'utf-8'), {client: true}); // Get template as a function
templates.template2 = ejs.compile(fs.readFileSync(filePath2, 'utf-8'), {client: true});
...
res.render('app.ejs', {templates: templates}); // Send templates in view
However, I can't get them in my view:
<script type="text/javascript">
var templates = <%- JSON.stringify(templates) %>; // Get templates object (object of functions)
</script>
is not working. they are functions on the server before I send them, but I don't know how to recover them. Do you have an idea ?
I tried a workaround, by changing them into String before sending them:
templates.template1 = templates.template1.toString();
Send them and then client side, transform them back in functions:
var template = new Function(templates.template1);
$.get('/artists', function(data) {
var html = template(data);
$('#artists-wrapper').html(html); // Sets HTML
});
But that won't work either.
Do you have an idea what I'm missing here?
And last, do you agree that compiling them server side before using the functions is better in terms of computation than rendering each template client-side?
Thanks for the help, and hope that will help anybody else!
You need to use the client option on the server side when you are compiling for the client. From the docs:
client When true, compiles a function that can be rendered
in the browser without needing to load the EJS Runtime
https://github.com/mde/ejs#options
Your server-side code snippet should be:
// Compile artist template
fs.readFile('views/artist.ejs', "utf-8", function(err, template) {
artist_template = ejs.compile(template, {client: true}); // Use client option
res.render('artists.ejs', {template: artist_template});
});

injecting form input from a post request into a get request using expressjs

I want to take form input from a form and inject it into a get request using expressjs. Not quite sure how to do it. I made a plnkr. I really dont want the answer just pointing in the right direction, so some sources to read would be great.
[enter code here][1]
I would use the query string to pass the data you need.
.post('/', function(res,req){
res.redirect('/?data=' + req.body.data);
})
.post('/', function(rgvfbbgbvbves,req){
req.body // this will give you all of the relevant POST
// this is where i need help i think
res.redirect('/');
})

unable to pass data from js to jade in node.js

I am reading a row from a table(emp) in cassandra.
I am trying to pass the result from js file to jade file to present the data on the user interface.
I have the js function as below
router.get('/cassandra', function (req, res)
{
client.connect(function(err){
});
client.execute('SELECT * FROM monica.emp WHERE empid= 324;', function (err, result) {
var user = result.rows[0];
console.log("here is the user", user.empid, user.firstname);
res.render('cassandra',{"cassandra":user});
});
});
my log is reading the result. But i am unable to pass the same to the UI from the jade file.
Below is my Jade File
extends layout
block content
p Cassandra
for i in cassandra
.c=i.empid+" "+i.deptid
I am getting a display something like below
Can someone please help me with where I am going wrong over here?
Looks like user is not an array. So just try cassandra.empid without a loop in the jade view
You might need to use a promise. Are you trying to render the template before the response comes back from the server?
try it
-for(var i in cassandra){
.c=#{cassandra[i].empid}+" "+#{cassandra[i].deptid}
-}
Your jade file should read
extends layout
block content
p Cassandra
#{cassandra.empid} #{cassandra.deptid}

Using AngularJS html5mode with express.js

Client-side:
when("/page/:id", {
templateUrl: "partials/note-tpl.html",
controller : "AppPageController"
});
$locationProvider.html5Mode( true );
Html:
<a ng-href="/page/{{Page._id}}">{{Page.name}}</a>
Server-side:
app.use("/page/:id", function( req, res ) {
res.send( req.params )
});
As a result I get empty page or just object with id. What's wrong?
Angular does not load note-tpl.html template
Might be because of the conflict from express templating engine vs angular.
What view engine are you using?
The use of {{}} might be handled by express and not angular. You can either change the server view engine to use other keywords.
Sounds like your server is not responding with note-tpl.html.
Are you sure your partials exist at that path? Have you used express.static?
Can help more with any error messages you get.

Categories