Accessing nested object with pug, json, htmlwebpackplugin - html-webpack-plugin

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

Related

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.

Meteor JS: include dynamic name template in layout

I have this basic layout. I want to include a dynamic header to be included in the template. +header should be like this +{{get_header_name}}. get_header_name is a helper function. I tried this idea but jade will throw an error. Any ideas how to make it dynamic?
basic.jade
template(name="basicLayout")
#main
header
+header // <--- make this a dynamic using helper (get_header_name)
+search
else
+yield
footer
+footer
If you don't use Iron Router, you can use Template.dynamic.
Define helper that returns session with template name:
Session.set('headerTemplateName', 'defaultHeader');
Template.basicLayout.helpers({
headerTemplate: function() {
return Session.get('headerTemplateName');
}
});
Use that helper in your basicLayout template:
+Template.dynamic template=headerTemplate
Now, when you change value of session headerTemplateName anywhere in the app, your header template will change according to it:
Session.set('headerTemplateName', 'anotherHeader');
If you use Iron Router, check out Layouts and Regions: https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#layouts

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

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,
},
}),
],
...

Having trouble defining global var in require.js

I'm trying to define a global object that i can reference across all of my modules. however, in the modules, i am unable to reference my path, and it's saying that "g" does not exist.
In main1.js, i have this:
requirejs.config({
paths: {
Underscore: 'lib/underscore/1.3.3/underscore.min',
Backbone: 'lib/backbone/0.9.2/backbone.min',
Globals: 'lib/backbone/ globalVars'
}
});
require([ 'views/pages', 'views/filters'], function(allPages, filters) {
filters.render();
allPages.render();
});
inside globalVars.js, i have this:
(function() {
var Globals = {
isDemo: false
}
console.log('in globalvars') // this shows in my console
}).call(this);
and finally, inside of view/pages.js, i have this:
define([
'Globals',
'Underscore',
'Backbone'
], function(g, _, Backbone){
console.log(g.isDemo) //<-- returns "TypeError: g is undefined"
If i use a define inside my main1.js like this:
define( 'Globals', function() {
return {
isDemo: true
}
})
it works just fine. I haven't had much luck with trying to figure out why this is not working. I'd like to be able to just include a path to the globalVars rather than boilerplate pasting a define block in each and every module that needs it, since changing isDemo to false would require updating many other module pages (main2.js, main3.js, etc) as well. thanks!
Well, to start with, your globalVars.js is not in the module pattern, so requirejs doesn't know what you're trying to register as the module. If you change that file to use the pattern, like the define you added to main1.js, you should be all set. Is there a reason you aren't defining it as a module?

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.

Resources