How do I deep compile nested handlebars content? - javascript

A project I'm working on uses Handlebars.js template system. It reads in content and when compiling the template injects the content where appropriate:
<div class="content">
<p>lorem ipsum</p>
{{{ content }}}
</div>
In this case the handlebars is compiled with a JS object who has a content property that is a string of text or HTML (hence the triple brackets).
However it is entirely possible that the content value (being text or HTML) could also include handlebars interpolation code:
var contentPassedToHandlebars = {
content: '<p>{{ foobar }}</p>',
foobar: 'foo'
};
Which currently outputs <p>{{ foobar }}</p> but what I would intend to get is <p>foo</p>.
Does handlebars have a facility for this nested content or is a custom helper required? ({{{custom_parse content}}})?
For context to this question
The situation derived from a build system (metalsmith) that reads in files as markdown, converted them to HTML, attach result to the content property of the file object, then parse a handlebars template which injects the file.content into it output. All this and I was hoping there was a solution to place handlebars or string interpolation into the markdown so the markdown files could have access to the same variables the templates have access to (obviously more global values in a config.json not the values associated with the file object being constructed).

There is no built in way to do this. You would have to manage you own pre-rendering process or internal helper.
For the solution I ended up running a pre-render before the official render. Although the code is not handlebars but instead part of the metalsmith-templates plugin, here is the solution I used.
This roughly translated to:
var contentPassedToHandlebars = {
content: '<p>{{ foobar }}</p>',
foobar: 'foo'
};
var x = Handlebars.compile(contentPassedToHandlebars.content)(contentPassedToHandlebars);
contentPassedToHandlebars.content = x;
Handlebars.compile(realTemplateSource)(contentPassedToHandlebars);

OR use this:
metalsmith-in-place
```
index.js
var inPlace = require('metalsmith-in-place')
....
.use(inPlace(true))
.....
Now, if you
write {{> footer }}
it will do the work.

Related

How to call a function inside a Template literal in node js

I am using node js , express. I am trying to call a function in template literal.
I made a module and import in main file and then add the function to app.locals and accessing in my views that works fine. But when i try to use it in template literals and also in my public file it give me error "currencyToWords is not defined".
I think in public file it makes sense because i make public folder static.
but in my views it is weird because when i use it in html it works but when i use it in template literal it gives error.
I want to use the currencyToWords function in template literals to change the response.
I have one solution that i can make the file in public folder and add the function in script in that file and import in footer but i dont want to do that.
Can anybody help me in solving the issue.
My app stucture
module.exports = { currencyConverter }
In app.js
app.js is my main file where i create server
var { currencyToWords } = require('./config/functions');
app.locals.currencyToWords = currencyToWords;
by adding in locals i can access it in my application any where
This code is working:
<div class="fix pull_right">
<h3><%= currencyToWords(property.propertyDetails.price)%></h3>
</div>
This is not working
var a =`
<p>${currencyToWords(property.propertyDetails.price)}</p>
`;
the above code is same but only difference is first one is use in ejs tags and second in ejs and template literals.
Here is the documentation from express about app.locals
app.locals
The app.locals object has properties that are local variables within the application.
console.dir(app.locals.title)
// => 'My App'
console.dir(app.locals.email)
// => 'me#myapp.com'
Once set, the value of app.locals properties persist throughout the life of the application, in contrast with res.locals properties that are valid only for the lifetime of the request.
You can access local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data. Local variables are available in middleware via req.app.locals (see req.app)
app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = 'me#myapp.com'

Use Angular templating in content which is injected using innerHTML

I have an Angular (4) template which injects what I give it using [innerHTML], and this cannot be changed as it's an external package. So originally I had something like this:
public getMessages(): InterfaceName {
return {
emptyMessage: `<span>Some content!</span>`
}
}
I then passed this into the template of the external element:
<external-element [messages]="this.getMessages()"></external-element>
This worked perfectly. However, the product I am working on needs to support internationalisation, so the strings all need to come from a separate JSON file, and Angular's TranslateService is used to retrieve the strings and render them. So in the internationalisation file, I had an array of messages which would each be posted to the emptyMessage object above. So I had this:
public getMessages(): InterfaceName {
const messages = this.translate.instant('PATH.TO.JSON.STRINGS');
return {
emptyMessage: `
<div>
<span *ngFor="let message of messages;">{{ message }}</span>
</div>`
}
}
However, this just rendered {{ message }}, presumably due to introducing the possibility of an XSS attack, Angular sanitised the HTML. I also tried to use [innerHTML]="message" but this just showed up blank.
So how can I get the content from the i18n file and render it, after which the content is injected using innerHTML, of which I have no control?

Can I load partials from another file in Mustache.js?

I'm trying to load in partials from a separate file while using mustache.js but it's proven difficult. The PHP implementation makes this very easy, but not so much in the JS side.
I've gone through the docs and can't find anything related to this, only using an object as a partial instead of a file.
Here's some sort of psuedocode to explain what I'm trying to do.
$.Mustache.load('/mustaches.php', function () {
var item = { thing: 'one' };
var partial = 'partials/actions.mustache';
$('.container').mustache(
'main_mustache',
{item: item},
partial
);
});
So, I'd like to be able to load a secondary file as a partial an include it with the template to be used so I don't have to duplicate code across all the different templates I use.
With something like Blaze I can import a template with {{> templateName}} but it doesn't seem to be quite so easy with Mustache.js.
If this isn't possible with Mustache, what other libraries would you recommend?
You could load both templates with mustache, and then pass one of them (the partial) to the one that should render the partial. Be aware that in order to make it work, in the mustache where you want to render the partial, the variable name should be enclosed in triple curly bracers in order to tell mustache that it should be html:
<div>
<h1>This is my title</h1>
{{{partial}}}
</div>
and then:
$('.container').mustache(
'main_mustache',
{item: item, partial: partial},
);

How does Partials / Template inheritance work in Mustache?

I don't really understand partials / template inheritance from Mustache / Hogan.js. As defined here and here you seem to must have two different files to make that work. I use it as follows in my (client side) page:
<template id="server-template">
{{#servers}}
<b>some html and {{> some other which I dont understand how to use}}</b>
{{/servers}}
</template>
<template id="room-template">
I want this in up there. (in the "partials" tag)
</template>
Thanks for helping. I compile them with this:
var source = $('#room-template').html(),
compiled = Hogan.compile(source)
$('#main').html(compiled.render(data))
Is that even possible?
The docs state that you must compile your partials separately, and then pass them to the render function:
In mustache.js an object of partials may be passed as the third
argument to Mustache.render. The object should be keyed by the name of
the partial, and its value should be the partial text.
var roomTemplateSource = $('#room-template').html();
var roomTemplate = Mustache.compile(roomTemplateSource);
Mustache.render(template, view, {
room: roomTemplate
});
<template id="server-template">
{{#servers}}
<b>some html and {{> room}}</b>
{{/servers}}
</template>

Getting access to data in jade template (to make static html)

I am trying to pass some data to jade template to generate static content. I do not know much about node.js and express, I don't use them as backend. I use jade as a template engine and to generate static html.
There are lot of request in jade issue list about having multi line code, and the owner comments
I'd like to promote keeping too much js out of the templates, maps etc
can be exposed via locals
if there's a lot of logic or objects etc within a template you should
be using app.helpers() etc, they can still be view-only helpers but at
least it keeps the templates cleaner
I am not quite sure how to do this in a grunt based environment. Basically, if I can get access to javascript variables (which may be a text, js or json file) in my jade template, so I can use the data in my template and generate static html files. What is the best way to do this?
Edit
To clarify further, I may have data like (say in a json file)
user1 = {link: '', lbl: 'User', txt: '.... lot 0f text ....'}
user2 = {link: '', lbl: 'User', txt: '.... lot 0f text ....'}
in my mixin, somehow I need to access user1, user2 etc in my jade template
.content
+colum(user1 )
+colum(user2 )
mixin colum(d)
.span4
h4
| #{d.lbl}
p
| #{d.txt}
Thanks a ton.
If you want to do it with grunt-contrib-jade try the data option:
jade: {
compile: {
options: {
data: function(dest, src) {
// Return an object of data to pass to templates
return require('./userData.json');
},
},
files: {
"dest.html": ["templates/*.jade"]
},
},
}
Here are the docs on it: https://github.com/gruntjs/grunt-contrib-jade#data
You can render your data in jade with: #{your_variable}
Hope this helps: The jade public API https://github.com/visionmedia/jade#readme
Update: after play around for awhile, I got this:
var jade = require('jade');
// Compile a function
var fn = jade.compile('p= data');
console.log(fn({'data':'test'}));
When I ran this code, I got: <p>test</p>. So here is how jade can work:
jade.complie(jadeString) is a function to determine what string that jade have to complie - the jadeString parameter, you can use fs module to load the content of your jade template and place it here. fn(jsonData) is the function that actually complie the jade template to html, jsonData is the data you want to use in the template.

Categories

Resources