Proper way to access DOM in Node + Express + Pug - node.js

I am learning to use the MVC architecture with Node, Express and Pug and am having trouble finding out how to properly access the DOM (in this case to add an EventListener). The documentation is quite terse and I wasn't able to find a solution elsewhere... which leads me to suspect I might be going about this all wrong?
This is the .pug file in question (simplified to highlight problem):
extends layout
block content
h1= title
div= foo
div
label Bar
input(
type='text'
name='city'
placeholder='start typing...'
)
input(type='submit' id='submitbtn' value='Submit')
- document.addEventListener('keydown', event => {console.log("Bleep!")})
- document.getElementById('submitbtn').addEventListener('click', () => doSomething())
^^^^^^^^
When Express attempts to render this page, I get the following error:
Only named blocks and mixins can appear at the top level of an
extending template
Am I barking up the wrong tree? If so, what is the proper way to access the DOM within the Node /
Express / Pug framework?

The error message is correct:
Only named blocks and mixins can appear at the top level of an extending template
In your example, you also have inline code at the top level of the template, which isn't allowed. You should indent those inside of the named block content.
Additionally, DOM javascript doesn't run while pug is compiling. It only runs in the browser once the Pug has compiled into HTML. In order to get that script to run, you need to place it in a script element just like you would if you were writing regular HTML.
extends layout
block content
h1= title
div= foo
div
label Bar
input(
type='text'
name='city'
placeholder='start typing...'
)
input(type='submit' id='submitbtn' value='Submit')
script.
document.addEventListener('keydown', event => {console.log("Bleep!")})
document.getElementById('submitbtn').addEventListener('click', () => doSomething())

Related

Express 4+pug disable layout

I want to ajax for blocks that without layout
Such as
extends layout
block content
p xxxx
I want to get the content in block
if !layout
include layout
The solution
If you don't want the standard pug layout then create a file that doesn't have extends layout in it:
doctype html
html(lang='en-us')
head
title Page Title
body
div Content goes here
You don't need to do anything in your app.js file to make this happen. You've probably figured out that none of the statements in your question work. This is all controlled in the pug template file.

Adding additional content blocks in KeystoneJS with handlebars

I'm using handlebars with KeystoneJS and am trying to extend the main import in the default template. At the moment it only includes the {{{body}}} tag imported through the view plus the partials that I'm using.
Is there any way to add a couple of other imports (i.e. intro content, page title, additional scripts). In the jade version on the demo site it just imports it as a content block. Is this a limitation of handlebars?
You can do this with handlebars just fine using partials.
Put your partial in the folder indicated below:
Then in your layout ('default.hbs' in this case) reference the partial like you would normally in handlebars.
<div id="header">
{{> navigation this}}
</div>
The '>' means insert partial.
In this case 'navigation' is the
partial name in the partials folder.
'this' is the data context. Its what you want to do with the 'locals.data' object passed into handlebars by keystone. Using 'this' will pass the whole lot through whereas doing something like 'locals.data.navigation' would pass the navigation object through to the partial making it directly accessible in the partial (good for DRY).
Hope that helps. The partials specific documentiation for handlebars is here if you are interested in looking into a few more things you can do with scope etc http://handlebarsjs.com/partials.html

"Unexpected identifier" when adding extends/block to wintersmith-jade content file

I am making a static website using Wintersmith alongside the wintersmith-stylus and wintersmith-jade plugins.
I want to add a specific CSS file in a help page. The help page is based off the "layout" template. When I try to use a block to insert the stylesheet into the html head, I receive the following error:
Line ##: Unexpected identifier
layout.jade
doctype html
html
head
block head
link(rel="stylesheet" href="/styles/layout.css")
body
...
help.jade
---
template: layout.jade
---
//- Error inducing code
extends ./layout.jade
block head
link(rel="stylesheet" type="text/css" href="../styles/help.css")
//- end of error inducing code
...
Even if I move the extends and block head lines on top of the metadata block containing template: layout.jade, I still receive the same error. Removing extends ./layout.jade results in the error lines position moving from 40 to 5 in my case.
My guess is the error is caused by the wintersmith-jade plugin, but even if that's the case I'm lost for how I would go about fixing it.
Since I wanted to use both Stylus and Jade (with Jade for both content and templates), I ended up moving over to Harp. Harp not only has Stylus and Jade "built-in", but it's also slightly simpler than Wintersmith.
It's quite a workaround, but I'd say it's actually an upgrade at the same time.
I'm not using wintersmith-jade, but it looks like that plugin shouldn't affect the regular templates in /templates (which is what I think you're referring to).
Looking at templates/article.jade, it looks like you should use just extends layout instead of extends ./layout.jade.
The default templates also do not have the metadata block, but maybe that's necessary for the plugin you're using.

Using template inline in Jade

I'd like to pass the name of a template file to my jade template and have it expand that template. I'm using node and express.
html
div(id="content")
extend #(content}
seems intuitive to me but it doesn't work. Is this possible and/or is there an alternative pattern to better achieve this?
After rethinking the pattern (I'm brand new to express and node), I realized a better solution. What I've done is taken the content (which was all static) and included it in block statements in multiple template files. I then serve those template files based on the route.
Say I have a layout page that has header and footer and multiple views: index, search, and getting started.
//layout.jade
html
head
block extra_headers
body
div(id="header")
div(id="content")
block content
div(id="footer")
//index.jade
html
block head
script(src="sss.js")
block content
| welcome to my home page
//results.jade
html
block head
script(src="search.js")
block content
| my search results
And so on with 'getting started'. My node code then looks like this:
app.get('/', function(res, req) {
return res.render('index'); // renders the index view.
});

Replace variables in jade without rendering to html

I am using jade as a kind of markup language for a thermal printer. That means on the website i render a print preview to html, and i am sending the jade(with custom tags) directly to the printer which interprets the tags for different text styles.
It works pretty well but now i would like to use also locals in that template but render only the locals not to html.
That means
p #{name}
should become
p John Doe
instead of
<p>John Doe</p>
Is there a possibility to do this with some function in the jade package ? Or do i need to write that from scratch. I also want to use jade "each" loop.
You can prefix it with a pipe symbol:
| p #{name}

Resources