node ejs reference error data not defined at eval when handing data to view - node.js

i've been closing in on a node application using express and ejs, but when i try to hand data to my view from the controller like so
var myData = {
theData: data
};
res.render(path.join(__dirname + '/../views/index'), myData);
i get a nice error
ReferenceError:.. myData is not defined eval (from ejs lib)
when trying to access myData in the view like so
var data = <%-myData%>;
or in any other way basically, i've tried stringifying the data, wrapping it in another object and stuff like that but it still just won't show up, i have the feeling i'm missing something really basic here, does anyone have an idea on how to fix this?

The second argument you pass to render() is an object containing the view variables you want to use in your template. So the error you are seeing makes sense. If you want to use myData in that way you'd have to do something like this in your controller/app:
res.render(..., { myData: JSON.stringify(myData) });

There's a silly mistake I make when I try to send data from the server.
Here's the mistake:
var data = <%=myData%>;
What you should do when passing it:
var data = <%-myData%>;
It's supposed to be a dash NOT an equal before the variable name.

If your are generating the template with the HtmlWebpackPlugin plugin, the data should be passed in your webpack configuration file, along with the templateParameters property.
For example:
...
plugins: [
new HtmlWebpackPlugin({
filename: __dirname + "/src/views/index.ejs",
template: "./src/views/index_template.ejs",
templateParameters: {
myData,
},
}),
],
...

Related

populate object properties using lambda expression in typescript

Newbie Alert! I feel silly asking this question but I need someone to teach me the correct syntax.
I have code that looks like this:
let thing: INewThing;
thing.personId = another.personId;
thing.address = another.work.address;
thing.greades = another.subjectInfo.grades;
thing.isCurrent = another.student.isCurrent;
I know it can be written cleaner. I want to use a lamda expression, something like this:
let thing: INewThing => {
personId = another.personId,
address = another.work.address,
grades = another.subjectInfo.grades,
isCurrent = another.student.isCurrent
} as IThingUpdate;
I have looked and looked for an example. I have yet to find one that works for me. It's just syntax but no matter what I try it doesn't work.
You're just looking to create a new object, which is a pretty different thing from a "lambda" (function). Just declare the object. You don't need a function.
const thing = {
personId: another.personId,
address: another.work.address,
// use the correct spelling below - no 'greades'
grades: another.subjectInfo.grades,
isCurrent: another.student.isCurrent,
};
If the another is typed properly, that should be sufficient.
If the another object had more properties using the same path, another option would be to destructure those properties out, then declare the object with shorthand, eg:
const originalObj = { prop: 'val', nested: { foo: 'foo', bar: 'bar', unwanted: 'unwanted' } };
const { foo, bar } = originalObj.nested;
const thing = { foo, bar };
Destructuring like this, without putting the values into differently-named properties, helps reduce typos - if a property starts out, for example, as someLongPropertyName, putting it into a standalone identifier someLongPropertyName and then constructing an object with shorthand syntax ensures that the new object also has the exact property name someLongPropertyName (and not, for example, someLongPRopertyName - which isn't that uncommon of a mistake when using the more traditional object declaration format).
But since all the paths in your another object are different, this approach wouldn't work well in this particular situation.

Accessing nested object with pug, json, htmlwebpackplugin

I seem to be having an issue accessing a value from a mixin when trying to use bracket notation. I have the following setup:
// in webpack plugins
new HtmlWebpackPlugin({
hash: true,
template: './assets/template/about.pug',
filename: 'about-us.html',
inject: true,
page: 'about',
locals: require('./assets/data.json'),
chunks: ['about']
}),
The json
// data.json (snippet)
{
"pages" : {
"about" : {"title" : "About Us","metaDesc" : ""},
}
}
Pug mixin
mixin pageTitle(thePage)
title= htmlWebpackPlugin.options.locals.pages[thePage].title
Using pug mixin
+pageTitle(htmlWebpackPlugin.options.page)
I get an error Cannot read property 'title' of undefined.
If I change that to htmlWebpackPlugin.options.locals.pages.about.title it will parse just fine.
If I change that to htmlWebpackPlugin.options.locals.pages[thePage] it will return [object Object] but I can't access any properties.
If I change that to htmlWebpackPlugin.options.page or just use thePage then "about" will be rendered.
I've done a typeof to check if it's a string. It is. I've tried putting it into a variable first. Same issue.
Any thoughts?
Why do you need notation in brackets? What is the purpose of this?
This record works title = thePage.pages.about['title']
I prefer the following entry ;)
In the file about.pug, make an entry at the very top.
block variables
- var path = self.htmlWebpackPlugin.options
You pass on to the function
// locals is the path to your json file
+pageTitle(path.locals)
Mixin should look like this
mixin pageTile(thePage)
title = thePage.pages.about.title
Here you have the whole example in addition with generating multiple subpages with pug-loader → photoBlog

Jade/Pug - appending to a class name

Hello I have a unique id in an object and I want to append it to a class name. I am trying to do something like the following but it isn't working:
myJadeFile:
.googleChartContainer-#{attendanceAnalytics.uid}
myRoute.js:
res.render('./edu/school_dashboard_elementary', { attendanceAnalytics:attendanceChart });
I suppose I could create a class name in my route and send it as a variable with something like:
var className = '.googleChartContainer-attendanceChart.uid}';
res.render('./edu/school_dashboard_elementary', { attendanceAnalytics:attendanceChart, attendanceClassName:className });
and then in the jade file:
#{attendanceClassName} //- output is .googleChartContainer-someUid?
I was wondering if there was a way to get the first approach to work correctly, or if there is another preferred way.
Thanks!
You have two choices. You can do it the JavaScript way with a string, like:
div(id=attendanceAnalytics.uid, class='googleChartContainer-' + attendanceAnalytics.uid)
or you create an JavaScript object containing keys and values to use them with the typical jade attribute div&attribute(object), like this:
- var attr = {"id": attendanceAnalytics.uid, "class": 'googleChartContainer-' + attendanceAnalytics.uid}
div&attribute(attr)
Take a look into the JadeLang Docs, chapter attributes.

Can I add attributes to a Backbone View?

I have been working with backbone for a while and I am now using a number of views. In some of my views I sometimes add custom attributes like:
var DataGrid = Backbone.View.extend({
className:"datagrid",
lookup: {
header: "", //Header wrapper row element
headers: [], //Views in header
body: "", //Body wrapper row element
rows: [] //Views in body
},
events: {
...
},
initialize: function() {
...
},
render: function() {
...
}
});
As you can see I have "lookup" as an extra attribute to the Object. I use DataGrid in a number of my views and I am experiencing a very strange behaviour. When I switch between views that use DataGrid, "lookup" would still be populated with the old data. I use "new" when creating a new DataGrid but I still find old data. Am I missing something?
EDIT: Following #rabs reply. I did a search on static variables in Backbone and found this: Simplify using static class properties in Backbone.js with Coffeescript
I know an answer has been accepted on this (a while ago), but as I came across this question while working on a backbone project recently, I thought it would be worth mentioning that you can define attributes as a function also. This is especially useful for views that need to have attributes set to values in their current models.
By defining attributes as a function you can do something like
var myObject = Backbone.View.extends({
attributes: function() {
if(this.model) {
return {
value: this.model.get('age')
}
}
return {}
}
});
Hope that helps someone
Declaring variables in this way the scope of the variable is to the class not the instance, similar to s static or class variable.
So yeah the lookup object will shared between your different instances.
You could pass the lookup object in to your instance when you create it that way it will behave as an instance variable.

How to add context helper to Dust.js base on server and client

I'm working with Dust.js and Node/Express. Dust.js documents the context helpers functions, where the helper is embedded in the model data as a function. I am adding such a function in my JSON data model at the server, but the JSON response to the browser doesn't have the function property (i.e. from the below model, prop1 and prop2 are returned but the helper property is not.
/* JSON data */
model: {
prop1: "somestring",
prop2: "someotherstring",
helper: function (chunk, context, bodies) {
/* I help, then return a chunk */
}
/* more JSON data */
I see that JSON.stringify (called from response.json()) is removing the function property. Not sure I can avoid using JSON.stringify so will need an alternative method of sharing this helper function between server/client. There probably is a way to add the helper functions to the dust base on both server and client. That's what I'm looking for. Since the Dust docs are sparse, this is not documented. Also, I can't find any code snippets that demonstrate this.
Thanks for any help.
send your helpers in a separate file - define them in a base context in dust like so:
base = dust.makeBase({foo:function(){ code goes here }})
then everytime you call your templates, do something like this:
dust.render("index", base.push({baz: "bar"}), function(err, out) {
console.log(out);
});
what this basically does is it merges your template's context into base, which is like the 'global' context. don't worry too much about mucking up base if you push too much - everytime you push, base recreates a new context with the context you supplied AND the global context - the helpers and whatever variables you defined when you called makeBase.
hope this helps
If you want stringify to preserve functions you can use the following code.
JSON.stringify(model, function (key, value) {
if (typeof(value) === 'function') {
return value.toString();
} else {
return value;
}
});
This probably doesn't do what you want though. You most likely need to redefine the function on the client or use a technology like nowjs.

Resources