How to change something dynamically in the main handlebars skeleton? - node.js

I am using handelbars as my templating engine and I am curious to whether I could edit the main handlebars file. What I can do at the moment is something like this:
main.handlebars:
<html>
<head>
</head>
<body>
<div id='headerBox></div>
<div id='contents'>{{{body}}}</div><!--all contents goes here-->
</body>
When I use this method I will could create templates e.g. home.handlebars etc.
But what If I wanted to change something dynamically in the main.handlebars? For example in my website, I would love to have a login form so I would like to have something like this in the main.handelbars:
<html>
<head>
</head>
<body>
<div id='headerBox>{{If logged in print name, if not print sign up}}</div>
<div id='contents'>{{{body}}}</div><!--all contents goes here-->
</body>
</html>
TLDR, how to I change something dynamically in the main handlebars skeleton.
Thanks!

You'll want to write a Handlebars Helper function. Since you didn't include anything about how you're verifying login, I'll write a little demo.
In your template file:
<div id='headerBox'>{{header}}</div>
Handlerbars.registerHelper('header', function() {
if (loggedIn) {
return //however you're getting a username
} else {
return Sign Up
}
});

Related

ejs include on click

I'm trying to create a dynamically included in an ejs page (using <%- include('partials/content') %>) on my node.js project.
Is there a way I can create a variable for the to-be-included page and change it on a button click?
Let's assume your partials/content file includes content like:
<h1>Lorem ipsum dolor sit amet</h1>
A file named partials/content2:
<h1>consectetur adipiscing elit<h1>
Your main template file would wrap the partials content by a <div> with the id result and include a script file where you select this <div> by using var $result = $('#result'); so you have it in a variable. Then you can register a click handler on your button. On click you request the wished template file and replace the content.
Main template:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div id="result">
<%- include partials/content.ejs %>
</div>
<button id="change">change</button>
<script>
var $result = $('#result');
$('#change').click(function() {
$result.load('/content2');
});
</script>
</body>
</html>
Then you need a controller on the backend like:
app.get('/content2', function (req, res) {
res.render('partials/content2');
});

Riot-tag inside of a loop

I have a xxx component, which when used with the riot-tag attribute and a standard HTML5 tag, works correctly: <article riot-tag="xxx"></article>. However when I use the riot-tag attribute inside of a loop, the tag is empty: <article each="{xxxTags}" riot-tag="{xxx}"></article>. Is using riot-tag in a loop possible at all? How can I make it work?
Additional explanation:
I have to generate several different, albeit similar components one by one. So I have an array to store them:
var xxxTags = [{tag: 'xxx'}, {tag: 'yyy'}, {tag: 'zzz'}];
Putting any of the textareas one by one manually for all of: xxx, yyy, zzz works fine and generates the respective components. However when I try to do it with each, they end up empty (no children) in chrome devtools, BUT otherwise identical to the ones put manually.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<my-tag></my-tag>
<!-- inlined tag definition -->
<script type="riot/tag">
<my-tag>
/*Standard, manual addition of different components (works)*/
<xxx></xxx>
<yyy></yyy>
<zzz></zzz>
/*Standard addition of same components in a loop (works)*/
<div each={myTags}>{tag}</div>
<br>
/*Addition of different components with "riot-tag" manually (works)*/
<div riot-tag="xxx"></div>
<div riot-tag="yyy"></div>
<div riot-tag="zzz"></div>
/*Addition of different components with "riot-tag" in a loop (DOESN'T WORK should look like the example above)*/
<div each={myTags} riot-tag="{tag}"></div>
this.myTags = [{tag: 'xxx'}, {tag: 'yyy'}, {tag: 'zzz'}];
</my-tag>
<xxx>
<p>X content</p>
</xxx>
<yyy>
<p>Y content</p>
</yyy>
<zzz>
<p>Z content</p>
</zzz>
</script>
<!-- include riot.js and the compiler -->
<script src="//cdn.jsdelivr.net/g/riot#2.2(riot.min.js+compiler.min.js)"></script>
<!-- mount normally -->
<script>
riot.mount('*');
</script>
</body>
</html>
Okay, looks, like the tags with riot-tag attribute are not mounted when generated with an each-loop (still looks like a bug?). For the above-mentioned code, adding this does the job:
this.on('mount', function() {
for(var i = 0; i < this.myTags.length; i++) riot.mount(this.myTags[i].tag);
});

meteor with flow router layout is rendered twice

I don't know why but my layout is rendered two times.
Here is my index.html:
<head>
<title>title</title>
</head>
<body>
{{>layout}}
</body>
Here is my layout:
<template name="layout">
{{#if canShow}}
{{>Template.dynamic template=content}}
{{else}}
{{> loginButtons}}
{{/if}}
</template>
So here without route my template is display just one time.
Here is my route:
FlowRouter.route('/', {
action() {
BlazeLayout.render("layout", {
content: "home"
});
}
});
But with this route my template is display a second time.
This is my helpers, I think there is nothing to do with this problem but we never know.
Template.home.onCreated(function() {
this.autorun(() => {
this.subscribe('post');
});
});
Template.layout.helpers({
canShow() {
return !!Meteor.user();
}
});
Template.home.helpers({
cats() {
return Posts.find({});
}
});
you don't need to render layout in the body.
The router will take care of the rendering.
so, just have
<body>
</body>
or don't even have it at all.
Edit: Thanks to Keith, I have a better understanding of my problem. Here is his comment:
one thing to keep in mind, all the html you write in meteor isn't kept as html. It all gets converted to javascript. Things like index.html do not get pushed to the browsesr. Meteor just takes all the html you write converts it to javascript and renders what it needs to based on what your code says. This is how it knows todynamically change and rerender html
For things like changing title of the head or add meta etc, we can do it directely in the javascript.
ex: Meteor - Setting the document title

Node Express EJS Dynamic template render

Hi I am trying to create dynamic template system in express, where I will get dynamic content from database and then render output in single index.ejs file.
Here is my index.js
router.get('/', function(req, res, next) {
var dataFrmDB = {
pageContent: "<%= data.pageTitle %>",
pageTitle: "home"
};
res.render('index', {data:dataFrmDB} );
});
And index.ejs contains:
<%= data.pageContent %>
What I should do so that I can render "home" as output. Is this possible?
I was working on something similar when we migrated from drupal to nodejs, I used ect for rendering instead of jade, its faster and much easier to deal with, However, its much better to use design pattern if you have a big dynamic website
js controller file
model.homepage(function(data)
{
res.render("homepage.ect",data,function(err,html)
{
// Do something before you send the response such as minification, or error handling
res.send(html);
});
});
ECT file
<html xmlns="http://www.w3.org/1999/xhtml" lang="ar" xml:lang="ar">
<head>
<%- #page.title.body %>
<%- #page.headerScript.body %>
<style type="text/css">#homepage-container{min-height:300px;color:#353535;float:right;width:100%}</style>
</head>
<body>
<% include 'upper_bar.ect' %>
<%- #page.headerAd.ads %>
<%- #page.notifications.body %>
<%- #page.autocomplete.body %>
<%- #page.redirect.body %>
<%- #page.navigation.body %>
<%- #page.overlayAd.ads %>
</body>
</html>
why bother so much?
You can easily do this using templatesjs
without any template engine.
let me show you how your work can be done using templatesjs
html file
<html>
<head>
<title> <%title%> </title>
</head>
<body>
your content goes here
</body>
</html>
now use templatesjs in you node.js file
var tjs = require("templatsjs");
router.get('/', function(req, res, next) {
var data = fs.readFileSync("./index.html");
tjs.set(data); // invoke templatesjs
var output = tjs.render("title","home");
/* this will replace the <%title%> tag
in the html page with actual title*/
res.write(output);
res.end()
});
i have used fs.readFileSync to keep simplicity of code you can use the asynchronus function if you want (fs.readFile).
a good referrence can be found here
Installation :
$ npm install templatesjs

Mongodb cursor is empty in ejs template(Async call inside ejs )

The following router calls the ejs template to populate the values of cursor in to the html page.
router.get('/users_loaded_disconnect', function(req, res) {
res.render('users_loaded_disconnect',
{cursor: req.db.collection('notify_user_state_collection').find({})});
});
user_loaded_disconnect.ejs
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<b> Users Loaded Disconnect </b>
<ul>
<% cursor.nextObject(function(err, item) { %>
<%= JSON.stringify(item) %>
<% }); %>
</ul>
</body>
</html>
The cursor does not work. However if the cursor is iterated within the router like the following code it prints the value
req.db.collection('notify_user_state_collection').find({}).nextObject(function(err, item) {
console.log(JSON.stringify(item));
});
What is wrong in iterating the cursor inside the ejs template ?
The cursor operation is asynchronous. Ejs will not wait for it to complete, and will continue to render the template before data is available. You can't effectively use callbacks inside ejs templates.

Resources