EJS not rendering ejs code on client side - javascript

I tried rendering EJS code that I sent from home.js to home.ejs as a string but it didn't work. I'm trying this now but nothing seems to work. My code is:
home.js
var templates = {};
templates.onScroll = fs.readFileSync('views/partials/onScrollAppendPost.ejs', 'utf-8');
res.render("users/home", {templates: templates});`
home.ejs
var template = new EJS({text: <%- JSON.stringify(templates.onScroll) %>}).update('#mainContainer', {postArr: postArr});
Edit:
What im trying to do is I want to detect when a user gets to the bottom of the page. With this code:
$(window).scroll(function () {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
//get post data and append post
}});
When the user gets to the bottom of the page i want to append ejs code to the page. Basically i want to communicate between ejs and js.

Based on the example at http://ejs.co, you first need to include a browser build of ejs in your page:
<script src="ejs.js"></script>
Then you can use EJS client-side like this:
var html = ejs.render('your template here', {postArr: postArr});
$('#mainContainer').html(html);
Here's I'm assuming postArr is set appropriately, possibly as the result of an AJAX request.
As you're using EJS to generate EJS it all gets a lot more difficult to understand but the relevant code in your home.ejs would be something like this:
var html = ejs.render(<%- JSON.stringify(templates.onScroll) %>, {postArr: postArr});
$('#mainContainer').html(html);
This assumes that the onScroll template doesn't include any other templates. You haven't specified whether home.ejs is being used to generate HTML or JavaScript so it's unclear precisely what other escaping considerations might apply but it's possible that won't be a problem.

Related

Passing Array to Script in EJS file [duplicate]

I'm working on a Node.js app (it's a game). In this case, I have some code set up such that when a person visits the index and chooses a room, he gets redirected to the proper room.
Right now, it's being done like this with Express v2.5.8:
server.get("/room/:name/:roomId, function (req, res) {
game = ~databaseLookup~
res.render("board", { gameState : game.gameState });
}
Over in board.ejs I can access the gameState manner with code like this:
<% if (gameState) { %>
<h2>I have a game state!</h2>
<% } %>
Is there a way for me to import this into my JavaScript logic? I want to be able to do something like var gs = ~import ejs gameState~ and then be able to do whatever I want with it--access its variables, print it out to console for verification. Eventually, what I want to do with this gameState is to display the board properly, and to do that I'll need to do things like access the positions of the pieces and then display them properly on the screen.
Thanks!
You could directly inject the gameState variable into javascript on the page.
<% if (gameState) { %>
<h2>I have a game state!</h2>
<script>
var clientGameState = <%= gameState %>
</script>
<% } %>
Another option might be to make an AJAX call back to the server once the page has already loaded, return the gameState JSON, and set clientGameState to the JSON response.
You may also be interested in this: How can I share code between Node.js and the browser?
I had the same problem. I needed to use the data not for just rendering the page, but in my js script. Because the page is just string when rendered, you have to turn the data in a string, then parse it again in js. In my case my data was a JSON array, so:
<script>
var test = '<%- JSON.stringify(sampleJsonData) %>'; // test is now a valid js object
</script>
Single quotes are there to not be mixed with double-quotes of stringify. Also from ejs docs:
"<%- Outputs the unescaped value into the template"
The same can be done for arrays. Just concat the array then split again.
I feel that the below logic is better and it worked for me.
Assume the variable passed to the ejs page is uid, you can have the contents of the div tag or a h tag with the variable passed. You can access the contents of the div or h tag in the script and assign it to a variable.
code sample below : (in ejs)
<script type="text/javascript">
$(document).ready(function() {
var x = $("#uid").html();
alert(x); // now JS variable 'x' has the uid that's passed from the node backend.
});
</script>
<h2 style="display:none;" id="uid"><%=uid %></h2>
In the EJS template:
ex:- testing.ejs
<html>
<!-- content -->
<script>
// stringify the data passed from router to ejs (within the EJS template only)
var parsed_data = <%- JSON.stringify(data) %>
</script>
</html>
In the Server side script:
ex: Router.js
res.render('/testing', {
data: data // any data to be passed to ejs template
});
In the linked js (or jquery) script file:
ex:- script.js
In JavaScript:
console.log(parsed_data)
In JQuery:
$(document).ready(function(){
console.log(parsed_data)
});
Note:
1. user - instead of = in <% %> tag
2. you can't declare or use data passed from router to view directly into the linked javascript or jquery script file directly.
3. declare the <% %> in the EJS template only and use it any linked script file.
I'm not sure but I've found it to be the best practice to use passed data from router to view in a script file or script tag.
This works for me.
// bar chart data
var label = '<%- JSON.stringify(bowlers) %>';
var dataset = '<%- JSON.stringify(data) %>';
var barData = {
labels: JSON.parse(label),
datasets: JSON.parse(dataset)
}
You can assign backend js to front end ejs by making the backend js as a string.
<script>
var testVar = '<%= backEnd_Var%>';
</script>
This should work
res.render("board", { gameState : game.gameState });
in frontend js
const gameState = '<%- JSON.stringify(gameState) %>'
Well, in this case you can simply use input text to get data. It is easy and tested when you use it in firebase.
<input type="text" id="getID" style="display: none" value="<%=id%>">
I know this was answered a long time ago but thought I would add to it since I ran into a similar issue that required a different solution.
Essentially I was trying to access an EJS variable that was an array of JSON objects through javascript logic like so:
<script>
// obj is the ejs variable that contains JSON objects from the backend
var data = '<%= obj %>';
</script>
When I would then try and use forEach() on data I would get errors, which was because '<%= obj %>' provides a string, not an object.
To solve this:
<script>
var data = <%- obj %>;
</script>
After removing the string wrapping and changing to <%- (so as to not escape html going to the buffer) I could access the object and loop through it using forEach()
Suppose you are sending user data from the node server.
app.get("/home",isLoggedIn,(req,res)=>{
res.locals.pageTitle="Home"
res.locals.user=req.user
res.render("home.ejs");
})
And now you can use the 'user' variable in the ejs template. But to use the same value using client-side javascipt. You will have to pass the data to a variable in the tag.
Passing ejs variable to client-side variable:
<script>
let user= '<%- JSON.stringify(user) %>';
</script>
<script>home.js</script>
Now you can access the user variable at home.js

load more button in nodejs

I have json file in series.pug page. When I click load more button want to make a request JSON file and add new element in the page. How can I make load more with using NodeJS or AJAX in pug page ?
extends layout
block content
.content(style='padding-bottom: 100px;')
#titles
.container
.row
.col-md-12
.form-group.text-center
label.col-md-2.text-right Quick Filter
input.search.col-md-6.text-center(type="text",placeholder='Search series quickly')
.row.list
-var count = 0
each value in data.entries
-if(value.programType =='series')
if(count!=18)
.col-md-3.col-sm-6.col-lg-2.series(data-item-id=++count)
figure.figure
a(href='/details/'+value.title)
img.figure-img.img-fluid.rounded(src=value.images['Poster Art'].url, alt=value.title)
.name.figure-caption.text-center.text-dark=value.title
.col-lg-12
a.btn.btn-primary.text-light.load Load More
script.
$('.load').click(function(){
var lastchild = $('.series').last().data('item-id');
$.ajax({
url: '/request',
method: 'POST',
data:{'lastchild':lastchild},
success: function(response){
}
});
});
You need to create a new route that you can make an API call to that returns only partial HTML. So something like this:
$.ajax('/loadmore?data=jsonFileName&template=pugTemplateName&startIndex=10&load=20');
Then in node, you'd have logic listening for this route, and when it comes in, you have node build out your html using your pug template.
So you're query params in this example would be:
data = .json file to pull data from
template = .pug file to use as template, should not `extend layout`
startingIndex = starting index for getting data from .json file
load = number items to render html for
Finally, you need to use a pug template that does not extend layout, so you only get a <div> back, and not an entire <html> document. In the pug template, pull in the json file, loop through the number of items you want (specified by startingIndex, and load), and then send the result of the pug file back to the browser.
The result of the AJAX call will be partial html, like a <div> or <ul>, but not an entire <html> document. You can then just append it to your webpage where it should be displayed.
Obviously, this is just a rough guide on how to do it, but if you set up the logic like this, you can use this call for any load-more functionality you might need on your site. If you post your source code to github, I might be able to give more specifics.

Server Side Templating Engine to render javascript

My use case is that I have portions of js code that I would like to render based on some user permissions, with server side language being PHP.
Now I am currently using the Fat Free Framework, but even in other frameworks like laravel, I have only been able to find templates that template HTML.
I know I can use the templating engines that exist to just have conditional template logic to print a <script> tag given certain user permissions, but I haven't found any examples of how to do the following in a .js file
Example:
PHP:
$visible = ['section1' => true, 'section2' => true];
//this just renders the js file
render('test.js', ['visible' => $visible]);
test.js:
`//this is some kind of templating format`
{{if(isset($visible['section1']))}}
var a = 'Gin';
function sectionA(){
//do something
}
{{endif}}
{{if(isset($visible['section3']))}}
var b = 'Rum';
function sectionB(){
//do something
}
{{endif}}
The result would be that test.js would be rendered as
var a = 'Gin';
function sectionA(){
//do something
}
Alright, so after some playing around, I've figured out a solution. when building the html, you can echo a script that has a src of whatever resource you want. on the server side, respond to the javascript src route by rendering a js file (using the templating engine) that has the templating markups in it, and things will work as I wanted them to :)

JavaScript jade modal variable

Folks,
I am trying to dynamically generate a modal. How would I find this piece of text and swap in the values?
I have a label, which I would like to dynamically set the content to from the table. Whats the proper way to find and replace the | .emailAddress ?
.modal-body
h3
span.label.label-info Email
| .emailAddress
script.
var $modal = $('#mymodal')
, $titleField = $modal.find('.modal-title')
, $emailField = $modal.find('| .emailAddress');
$('body').on('show.bs.modal', '.modal', function () {
var mid = $(event.target).closest('tr').data('id');
var email = $(event.target).closest('tr').data('email');
$titleField.text(email);
$emailField.text(email);
});
You don't explain how you're using Jade, there are two versions:
server side, your client get an generated HTMl
client side, you compile your Jade template to JavaScript and load the JS file in the client.
For your problem there are two solutions:
You change the HTML which is already generated because the user action can be triggered after the page is loaded. (this is how your solution looks like, but this has nothing to do with Jade!)
You reload the Jade template: remove the old template from the DOM and pass the use data (from the modal action) to the new template, only works for solution 2.
But maybe your error is this selector, which is not correct:
$modal.find('| .emailAddress');
try this:
$modal.find('.emailAddress');

Accessing Express.js local variables in client side JavaScript

Curious if I'm doing this right and if not how you guys would approach this.
I have a Jade template that needs to render some data retrieved from a MongoDB database and I also need to have access to that data inside a client side JavaScript file.
I'm using Express.js and sending the data to the Jade template as follows :
var myMongoDbObject = {name : 'stephen'};
res.render('home', { locals: { data : myMongoDbObject } });
Then inside of home.jade I can do things like :
p Hello #{data.name}!
Which writes out :
Hello stephen!
Now what I want is to also have access to this data object inside a client side JS file so I can manipulate the Object on say a button click before POSTing it back to the server to update the database.
I've been able to accomplish this by saving the "data" object inside a hidden input field in the Jade template and then fetching the value of that field inside my client-side JS file.
Inside home.jade
- local_data = JSON.stringify(data) // data coming in from Express.js
input(type='hidden', value=local_data)#myLocalDataObj
Then in my client side JS file I can access local_data like so :
Inside myLocalFile.js
var localObj = JSON.parse($("#myLocalDataObj").val());
console.log(localObj.name);
However this stringify / parsing business feels messy. I know I can bind the values of my data object to DOM objects in my Jade template and then fetch those values using jQuery, but I'd like to have access to the actual Object that is coming back from Express in my client side JS.
Is my solution optimal, how would you guys accomplish this?
When rendering is done, only the rendered HTML is send to the client. Therefore no variables will be available anymore. What you could do, is instead of writing the object in the input element output the object as rendered JavaScript:
script(type='text/javascript').
var local_data =!{JSON.stringify(data)}
EDIT: Apparently Jade requires a dot after the first closing parenthesis.
I do it a little differently. In my contoller I do this:
res.render('search-directory', {
title: 'My Title',
place_urls: JSON.stringify(placeUrls),
});
And then in the javascript in my jade file I use it like this:
var placeUrls = !{place_urls};
In this example it's used for the twitter bootstrap typeahead plugin. You can then use something like this to parse it if you need to :
jQuery.parseJSON( placeUrls );
Notice also that you can leave out the locals: {} .
Using Jade templating:
If you are inserting #Amberlamps snippet of code above an included static HTML file, remember to specify !!! 5 at the top, to avoid having your styling broken,
in views/index.jade:
!!! 5
script(type='text/javascript')
var local_data =!{JSON.stringify(data)}
include ../www/index.html
This will pass in your local_data variable before the actual static HTML page loads, so that the variable is available globally from the start.
Serverside (using Jade templating engine) - server.js:
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.get('/', ensureAuthenticated, function(request, response){
response.render('index', { data: {currentUser: request.user.id} });
});
app.use(express.static(__dirname + '/www'));
You don't need to pass the locals variables in render call, locals variables are globals. On your pug file call don't put keys expression e.g #{}. Just use something like:
base(href=base.url)
where base.url is app.locals.base = { url:'/' };
Have you heard of socket.io? (http://socket.io/).
An easy way to access the object from express would be to open a socket between node.js and your javascript. This way data can be easily passed to the client side and then easily manipulated using javascript. The code wouldn't have to be much, simply a socket.emit() from node.js and a socket.on() from the client. I think that'd be an effective solution!

Categories

Resources