Can I retrieve a variable from a express function into a script of a pug template? - express

I have a express function that retrieves one variable(array) from mongoDB
app.get('/route',function(req,res,next){
User.find()
.exec(function(err,result){
if(err) throw err
var outputMessage=result[0].message.split(/\\n/g)
var myBooks=[]
for(var i=0;i<outputMessage.length;i++){
myBooks.push(outputMessage[i])
}
res.render('index',{books: myBooks})
})
}
And a pug template index.pug:
html
head
script(type='text/javascript')
for book in books /*books coming from the express function in res.render('index',{books: myBooks}) */
data.addRows([book,1]) /*data.addRows are object and method from Google Charts*/
Is it posible to use a variable from the express function within a script of the pug template (and within the head)

You can store books array into a javascript variable and then iterate over it using javascript foreach:
html
head
script(type='text/javascript').
var books = !{JSON.stringify(books)};
books.forEach( function (book) {
data.addRow([book,1]);
});
Do not forget dot . after script(type='text/javascript') that tells pug not interpreting the next code

Related

How can I create a JavaScript global variable?

This is the part of my .html file, where I use an xmlhttp request, and then try to access the JSON object outside of a function.
''''
<html>
<head>
<title>make_activities_table.html</title>
</head>
<body>
<script>
var act_obj_array;
// Get file activities.json and create JSON object
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if ( this.readyState == 4 && this.status == 200 ) {
act_obj_array = JSON.parse( this.responseText);
}
console.log(this.responseText);
console.log('Inside function = ' + act_obj_array);
};
xmlhttp.open( "GET", "activities.json", true);
xmlhttp.send();
console.log( 'Outside function = ' + act_obj_array);
</script>
</body>
''''
I'm trying to access the JSON object 'act_obj_array' outside of the xmlhttp.onreadystatechange function. From what I read, in JavaScript, to make a variable global, you define it outside of any function, which, clearly I have done here. But when I console.log 'act_obj_array, outside the function, I get undefined.
activities.json, is a file, that exist in the same directory of my web hosting's server. It is a JSON formatted file. I can see the information in the file quite clearly when I console.log( this.responseText );
What do I need to do to create a JSON object from an xmlhttp request, and then be able to access the JSON object from the rest of my code?
Well, since no one wanted to answer, I came up with a solution, and, I want to work on a second solution.
The solution I have now, I added a function after the line, inside a function:
act_obj_array = JSON.parse( this.responseText);
which is a function, that builds my table from my JSON object. At first, I just added the script in the body of the document, but, then, I defined the function in an external JavaScript sheet. This looked much cleaner.
The other solution, and one I haven't played with yet, is to use the 'fetch' method to read in my JSON file. That way, I may not have to use a function to create my JSON object.

How to render string into javascript in pug

So i am using Express and create an MVC application. I have a list of email that i want to put into javascript variable in the front end and create an auto complete
so currently the controller looks like this:
controller.js
res.render('/page',{emails: emails})
the emails is a JSON structured, can be stringified if needed. and my pug template is as follow
div
input (type = "text" id="suggestion")
div (class = "custom-suggestion" id="suggestion-list")
and at the end, i override custom scripts block with:
script.
var emailList = ///////////i want the email from controller's data
How can i achieve this? Any suggestion as long as i can pass the data to the javascript side will be considerable
EDIT
To make the code clearer:
app.js
var app = express();
app.set('view engine', 'pug');
router = express.Router();
router.get('/',function(req,res,next){
emails = ['abcd#abc.com','def#def.com','123#123.com'];
res.render('index', {emails:emails})
})
app.use(router);
index.pug
extend layout
block content
h1= title
block scripts
script
emails= emails /// not working
////////////// how to render this line as
////////////// emails = ['abcd#abc.com','def#def.com','123#123.com']
You can use interpolation to do this:
script.
emails= !{JSON.stringify(emails)};
Note that there's a period after the script tag, this tells pug to treat the content inside the tag to be plain text. Without that period it will create a script tag then an email tag (<script><email></email></script>) which is not what you want here.
Now that you're in plain text mode you can output the template variable into a JavaScript variable using an unescaped interpolation command (!{...}) with a stringify inside.

give context from route to pug mixin

I am trying to give context through express route to pug file containing only one mixin. But when i try to render that file, it just do nothing.
This is my express route
app.post('/comment', (req, res) => {
const test = {
text: 'working',
};
res.render('comment-section', test);
});
And here is my pug file mixin
mixin comment()
div.comment-content
div.row
div.col-lg-1
a(href="#")
img(src="img/default_profile.jpg").comment-profile-img
div.col-lg-10
p.user-comment
| Comment //- <--- Here i would like to use the test object this way {#text}
div
textarea(name="post_content" placeholder="Comment something" rows="1").comment-textarea.post-comment-message
How can i make the pug mixin take the context (test object) from the route and use it.
Thanks in advance!
Not pro at pug but I think you should provide the arguments you want to use explicitly:
mixin comment(text)
div.comment-content
div.row
div.col-lg-1
a(href="#")
img(src="img/default_profile.jpg").comment-profile-img
div.col-lg-10
p.user-comment= text //- or #{text}, assuming {#text} was a typo
div
textarea(name="post_content" placeholder="Comment something" rows="1").comment-textarea.post-comment-message
Now you can use it as follows
- var text = '<- var should already exist when locally provided'
#comment-section
+comment(text)

Grabing Dojo Original Object given Dom Id

I have a DOJO Editor that I add in JS using the method createEditor
require(["dijit/Editor"],
function(Editor){
this.createEditor = function(idToReplace){
var myEditorA = new Editor({
height: '50px',
plugins:['bold','italic']
}, document.getElementById(idToReplace));
myEditorA.startup();
}
});
I need the text inside the Editor after it has been changed.
I hooked up the method getEditorText but it is failing to do as I want it to do.
require(["dijit/Editor"], "dojo/dom",
function(Editor, dom){
this.getEditorText = function(idofEditor){
//Editor myEditor =Editor(null, dom.byId(idofEditor)); does not work either
var myEditor = dom.byId(idofEditor);
var content = myEditor.get("value");
});
The value that I need is stored in the attribute "value" in the Editor.
If I store myEditorA in a global variable I can get the content but I need the correct syntax to avoid working with unnecessary global variables
In Dojo widgets (dijit) and DOM nodes are treated seperately. For DOM nodes you indeed need to use the dojo/dom module and the function byId(). For widgets however, you need the dijit/registry module and then you can get the widget by its DOM node like this:
require(["dijit/registry", "dojo/dom"], function(registry, dom) {
var myEditor = registry.byNode(dom.byId(idofEditor));
});
But because the registry also saves your editor with the same ID as your DOM node, you can also access it directly (without using the DOM node) like this:
require(["dijit/registry"], function(registry) {
var myEditor = registry.byId(idofEditor);
});
I made an example JSFiddle which you can find here.

How to structure a complex web app with RequireJS

I saw there is somes questions related to mine (like this interesting one), but what I wonders is how to do it correctly, and I couldn't find it via the others questions or the RequireJS documentation.
I'm working on a quite heavy web application that will run in only one html page.
Before RequireJS, I used to do a lot of JS modules with public methods and connecting them via the on event on the Dom READY method, like this :
var DataList = function () {
this.base = arguments[0];
this.onUpdate = function (event) { ... }
}
$(function () {
var dataList = {}; DataList.apply(dataList, [$('#content')]);
$('table.main', dataList.base).on ('update', dataList.onUpdate);
});
With RequireJS, I can easily see that I can split DataList and all others classes like this on individual files, but what about the $(function () {}); part?
Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?
Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example :
require(['Datalist'], function(dataList) {
dataList.init($('#content'));
});
What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work.
I don't know, the way of thinking with RequireJS lost me a bit :/
How would you do?
"Can I still keep it this way, but instead of the DOM ready function of jQuery, I put the events on the main function() of the RequireJS, when my primary libs are loaded?"
If you separate the functions or 'classes' into modules then you can use the RequireJS domReady function:
require(['module1'], function(module1) {
domReady(function(){
// Some code here ftw
})
});
The benefit here is the domReady function will allow downloading of the modules instantly but won't execute them until your DOM is ready to go.
"Or do I have to change the way I create JS "classes", to include a init function maybe, that will be called when I do a, for example"
You won't need to change the way you interact with your code this way, but you can probably improve it. In your example I would make DataList a module:
define(function(require) {
var $ = require('jquery');
var DataList = function () {
this.base = arguments[0];
};
DataList.prototype.onUpdate = function() {
};
return DataList;
});
require(['data-list'], function(DataList) {
var data = {};
// Call DataList with new and you won't need to set the context with apply
// otherwise it can be used exactly as your example
new DataList(data);
});
"What annoys me the most is that since I have only one html file, I'm afraid the require() will have to load a huge list of files, I'd prefer it to load just libs that, them, would load sub libs required to work."
Make your code as modular as you want/can and then use the optimiser to package it into one JS file.