Handlebars partial display name instead of template in loopback - handlebars.js

I have a wired problem of partial showing the name instead of the template itself in loopback. For some reason the partials are not getting registered. Following is my code ... I am sure I am missing something but not able to quite figure it out. All help the appreciated. I am using express-handlebars as the bridge between loopback and handlebars
In server.js, I have the following code
var handlebars = require('handlebars');
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout : '',
helpers : {},
extname : 'handlebars'
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.set('views', __dirname + '/../client/views');
Following is my express router code ...
router.get('/', function(req, res) {
res.render('index', {
partials: {
mypartial : 'awesomepartial'
},
});
});
... and the partial tag from index page. The partial page is just plain html code
{{> mypartial}}
.... when the index template gets executed, instead of seeing the text from awesomepartial.handlebars template (which resides in same directory as index.handlebars) I see following text
awesomepartial
What could I be doing wrong? Why is handlebars sending the partial name back instead of template code. I tried various combinations which makes me believe that path may not be a problem.

Following is the working code ...
var handlebars = require('handlebars');
var exphbs = require('express-handlebars');
var hbs = exphbs.create({
defaultLayout : '',
helpers : {},
partialsDir : __dirname + '/../client/views',
extname : 'handlebars'
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.set('views', __dirname + '/../client/views');
router.get('/', function(req, res) {
res.render('index', {
mypartial : 'awesomepartial'
});
});
{{> (lookup . 'mypartial'}}

I believe you need to use a dynamic partial which is done like so:
{{> (mypartial)}}
basically just wrapping the variable with parens. See docs for "Dynamic Partials" here: http://handlebarsjs.com/partials.html

Related

please how can l add a runtime option to disable the check or this warning

I am creating a contact form that will display some messages on screen for the user to know that form was submitted successful
but,l am always receiving error message in my git terminal. Below is the error message.
Handlebars: Access has been denied to resolve the property "message" because it is not an "own property" of its parent.
You can add a runtime option to disable the check or this warning:
See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details
Below is server.js and message.handlebars code;
app.post('/contactUs',function(req,res){
console.log(req.body);
//res.send('thanks');
const newMessage = {
fullname: req.body.fullname,
email: req.body.email,
message: req.body.message,
date: new Date()
}
new Message(newMessage).save(function(err, message){
if (err){
throw err;
}else{
Message.find({}).then(function(messages){
if(messages){
res.render('newmessage',{
title: 'Sent',
messages:messages
});
}else{
res.render('noMessage',{
title: 'Not found'
});
}
});
}
});
});
<h1>Thank you for contacting</h1>
{{#each messages}}
<p>{{fullname}}</p>
<p>{{email}}</p>
<p>{{message}}</p>
<small>{{date}}</small>
<hr>
{{else}}
<p>No messages</p>
{{/each}}
<button class="btn btn-success">Contact Again</button>
I'm guessing your doing the same dating app tutorial I am working on. I solved this problem by following the given link: https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access
Then I downloaded the package npm install #handlebars/allow-prototype-access
Then in server.js add:
const express = require('express');
const Handlebars = require('handlebars')
const expressHandlebars = require('express-handlebars');
const {allowInsecurePrototypeAccess} = require('#handlebars/allow-prototype-access')
Scroll down in server.js to app.engine:
// setup view engine
app.engine('handlebars', exphbs({
defaultLayout: 'main',
}));
app.set('view engine', 'handlebars');
Then add: handlebars: allowInsecurePrototypeAccess(Handlebars)
It should look like this:
// setup view engine
app.engine('handlebars', exphbs({
defaultLayout: 'main',
handlebars: allowInsecurePrototypeAccess(Handlebars)
}));
app.set('view engine', 'handlebars');
I hope this helps. Good Luck.
you can add .lean() to your model for example await Basic.findById(result.id).lean()
This may be happening because of the latest version of Handlebars, but this can be solved by adding a dependency to handlebars.
npm i -D handlebars#4.5.0
Just use the exact same version of "express-handlebars" , which was shown in the tutorial. The latest version of handlebars is causing the problem.
Atleast doing this , worked for me.
This worked for me, pretty similar to the first answer:
const express = require('express');
const handlebars = require('handlebars')
const expressHandlebars = require('express-handlebars');
const { allowInsecurePrototypeAccess } = require('#handlebars/allow-prototype-access')
// configuration express for handlebars
app.engine('hbs', expressHandlebars({ extname: 'hbs',
defaultLayout: 'mainLayout',
handlebars: allowInsecurePrototypeAccess(handlebars),
layoutsDir: __dirname + '/views/layouts/' })
);
const Handlebars=require('handlebars')
const {allowInsecurePrototypeAccess} = require('#handlebars/allow-prototype-access')
app.engine('handlebars',exphbs({defaultLayout:'main',
handlebars: allowInsecurePrototypeAccess(Handlebars)
}));
app.set('view engine','handlebars');
this is happening to a new version of express-handlebars module. To fix this pass the following runtime options into handlebars engine configuration.
first of all, type a following command in your terminal and hit enter:
npm install #handlebars/allow-prototype-access
and
npm install handlebars
after that write these code into your server.js file
const Handlebars = require('handlebars')
and
const {allowInsecurePrototypeAccess} = require('#handlebars/allow-prototype-access')
then add this line:
handlebars: allowInsecurePrototypeAccess(Handlebars)
in your setup view engine.
I also faced the same problem while using mongoose with hbs, but I was using async / await instead of promises. So I tried .lean() method
like #Boniface Dennis said that solved my problem.
For more information please checkout link
//the syntax goes like this
const messages = await Messages.find({}).lean();

using data from script file in handlebars template

I'm working on node.js/express app and I'm using handlebars as a template engine. I know how to send data to hbs template using res.render('results',{data}) but in this case this is not possible. I'm trying to display some data generated in script.js on handlebar template page but I can't make it.
I have tried to include
<script id="selected-analysis" type="text/x-handlebars-template">
{{#if visibility}}
{{city}}
{{/if}}
</script>
<div class="content-placeholder"></div>
on results.hbs page and code bellow on script.js page
let theTemplateScript = document.getElementById("selected-analysis").innerHTML;
let theTemplate = Handlebars.compile(theTemplateScript);
let display = {
"visibility":true,
"city":'beo'
}
let theCompiledHtml = theTemplate(display)
document.querySelector('.content-placeholder').innerHTML += theCompiledHtml
On main.hbs I have
<script src="/dist/handlebars-v4.4.3.js"charset="utf-8"></script>
In my app.js file I have set handlebars middleware
app.engine('.hbs', exphbs({
defaultLayout:'main',
helpers:helpers,
extname:'.hbs'
}))
app.set('view engine', 'hbs')
could anyone tell me what I'm doing wrong.
thanks
Please try using app.set('view engine', '.hbs'); in app.js.
Please modify app.js as below
var express = require('express');
var exphbs = require('express-handlebars');
var app = express();
app.engine('.hbs', exphbs({
defaultLayout:'main',
helpers:helpers,
extname:'.hbs'}));
app.set('view engine', '.hbs');

How to pass functions to capture events in custom component in Meteor with Blaze

I want to know how to bind/set template-passed-parameter-value to click event of an item in the template in Meteor.
I'm using Meteor 0.7.0.1 with Blaze UI package. My main idea is to build a re-usable custom components in Meteor with Blaze template engine.
I have the following component which is working fine at the moment but I want this to be more customizable and remove some dependencies.
This is my component template named postLinks
<template name="postLinks">
<div id="link-popover-wrapper" >
<ul class="link-popover">
{{#each linkOptions}}
<li><a tabindex="-1" class="link-action" id="link-{{value}}" href="#">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
</template>
This postLinks component is used in the myPostItem helper.
Template.myPostItem.events({
'click .post-item-link-picker': function (evt, tmpl) {
var tmpPostId = this._id;
var tempData = {linkOptions:[{label:'Favorite', value : 'favorite'},{label:'Wish list', value : 'wishlist'},{label:'Later', value : 'later'}, {label:"Read", value:"read"}]};
var linkContent = Template.postLinks(tempData);
$(".item-link-picker").popover({
content: linkContent, html: true, placement: 'bottom', trigger: "manual",
template: "UI_POPOVER_TEMPLATE"});
$("#item-link-picker-"+tmpPostId).popover('show');
},
'click .link-action': function (evt, tmpl) {
//.... some code here to update link selection in db
}
});
Above code is working fine and I want to improve it to have following
Pass item click event externally to be bind to link-action like
After above two changes it will look like :
Template.myPostItem.events({
'click .post-item-link-picker': function (evt, tmpl) {
var tmpPostId = this._id;
var tempData = { itemClick:function(){}, linkOptions:[{label:'Favorite', value : 'favorite'},...]};
var linkContent = Template.postLinks(tempData);
$(".item-link-picker").popover({
content: linkContent, html: true, placement: 'bottom', trigger: "manual",
template: "UI_POPOVER_TEMPLATE"});
$("#item-link-picker-"+tmpPostId).popover('show');
}
});
I lack knowledge how/where to bind that passed event handling function to link-action elements in template or helper. I really appreciate if anybody could help to find a way to do that.
You go the other way around and use jQuery event triggering system, so
Template.myPostItem.events({
'click .link-action': function (evt, tmpl) {
$(evn.target).trigger('post-link-action', this /* extra data */);
},
});
This event can be easily catched in any parent template:
<template name="someOtherTamplate">
{{> myPostItem}}
</template>
Template.someOtherTemplate.events({
'post-link-action': function (evt, tmpl, extra) {
// the user of your component can define their custom behavior here
},
});
Please note that the event extra parameter will only be supported in the next Meteor release. Currently (0.8.0) it is included in the devel branch.

handlebars - cannot read property of undefined

I have a script that executes once a modal is launched. The js to configure the js object is:
var source = $("#print-script").html();
var template = Handlebars.compile(source);
var data = {
image: image,
title: title,
caption: subtitle,
category: template
};
$("#print-template").html(template(data));
All the variables are set above the object declaration and are working. My html reads:
<script id="print-script" type="text/x-handlebars-template">
<div class="print-only" id="print-template">
<img src="{image}"/>
<h2><span class="icon"></span>{category}</h2>
<h3>{title}</h3>
<p class="headline">{caption}</p>
<div class="description">{long_description}</div>
</div>
</script>
I'm getting a Uncaught TypeError: Cannot read property 'image' of undefined. I have confirmed that the object (data) is being populated with content. Thoughts?
I'd guess that the problem is right here:
var template = Handlebars.compile(source);
var data = {
//...
category: template // <------------------- oops
};
Note that template is the compiled template function there so when the template tries to fill in {category}, it will execute the template function. But the template function is expecting some values to fill in the template with and then it is called through {category}, those values won't be there and you'll get a TypeError. Run these two demos with your console open and you should see what's going on:
Error using category: template:
http://jsfiddle.net/ambiguous/9wEyS/
Works using category: function() { return 'string' }:
http://jsfiddle.net/ambiguous/YgfZx/
turns out there needs to be another object in the data:
var data = { print:{
image: featuredImage,
title: title,
caption: subtitle,
category: template
}
};

Scripterror when using RequireJS with .NET controls

I'm having a bit of an issue with RequireJS.
I have a .NET site with several controls that contains JS code which requires parameters generated by .NET. I've been trying to implement RequireJS into my site, but I ran into a small problem.
I've included the script tag that references RequireJS at the top of the page, as well as reference to main.js within that script tag. Inside my main.js I have the following code;
require.config({
paths: {
'jquery' : '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min'
}
});
Then I have a web control that is supposed to display a flash video. This web control contains the following piece of code;
require(['jquery'], function ($) {
if (!eval('<%= FlashAvailable.ToString().ToLowerInvariant() %>')) {
var url = '<%= FallbackImageUrl %>';
if (!url) {
$("#flashcontent").remove();
}
return;
}
var link = '<%= Page.ResolveUrl("~/Templates/AlloyTech/scripts/slideshow.swf") %>';
var width = '<%= Width %>';
var height = '<%= Height %>';
var variables = { xml: '<%= ConfigXml %>' };
var params = { wmode: 'transparent' };
var attributes = { };
swfobject.embedSWF(link, 'flashcontent', width, height, '10', false, variables, params, attributes);
});
This should be working fine right? However, executing the page results in two sets of errors.
1. GET http://episerversite6/scripts/jquery.js 404 (Not Found)
2. Uncaught Error: Script error http://requirejs.org/docs/errors.html#scripterror
Why is it trying to find jquery.js when I've defined the path for jquery is 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min'. I've tried adding a second parameter for the path, which is a local fallback jQuery file, and that makes everything work, but I'd still get the first error in my console.
Secondly, why am I getting the scripterror message? I've checked my code several times and I can't seem to find anything wrong with it. Does it have something to do with the code being executed before jQuery has time to load?
So I guess what I'm asking is, what's the best way to use RequireJS with inline scripts? I hope someone can help. Thanks in advance.
It seems I have misunderstood how RequireJS works and the need to rewrite my code accordingly.
So what I decided to do instead is append all ASP.NET generated variables to the elements they're affecting as data-* attributes, and moving all JavaScript codes to individual files which are then referenced in the main.js script that runs on page load. The data-* attribute values are fetched later when the script and its dependencies have been loaded.
So here's what I did to the project I mentioned in my initial question, which is actually an EPiServer CMS demo project called Alloytech.
Flash.ascx
<div id='flashcontent' data-flash-available="<%= FlashAvailable.ToString(CultureInfo.InvariantCulture).ToLowerInvariant() %>"
data-fallback-image="<%= FallbackImageUrl %>"
data-flash-link="<%= Page.ResolveUrl("~/Templates/AlloyTech/scripts/slideshow.swf") %>"
data-flash-width="<%= Width %>"
data-flash-height="<%= Height %>"
data-flash-variables="<%= ConfigXml %>">
<img src='<%= FallbackImageUrl %>' alt='<%= FallbackImageAlt %>' />
</div>
main.js
require.config({
shim: {
'swfobject' : {
exports: 'swfobject'
}
},
paths: {
'jquery': ['http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min', '/Scripts/jquery-1.7.2.min'],
'alloytech': '/templates/alloytech/scripts/alloytech',
'mobile': '/templates/alloytech/scripts/mobile/mobile',
'swfobject': '/Templates/AlloyTech/scripts/swfobject'
}
});
define(['jquery', 'alloytech', 'mobile', 'swfobject'], function ($, A, M, swfobject) {
$.fn.addFlash = function () {
return this.each(function () {
var el = $(this);
var flashAvailable = el.data('flash-available'),
fallbackImage = el.data('fallback-image'),
flashLink = el.data('flash-link'),
flashWidth = el.data('flash-width'),
flashHeight = el.data('flash-height'),
flashVariables = el.data('flash-variables');
if (!eval(flashAvailable)) {
var url = fallbackImage;
if (!url) {
el.remove();
}
return;
}
var link = flashLink;
var width = flashWidth;
var height = flashHeight;
var variables = { xml: flashVariables };
var params = { wmode: 'transparent' };
var attributes = {};
swfobject.embedSWF(link, 'flashcontent', width, height, '10', false, variables, params, attributes);
});
};
$(function () {
$("#flashcontent").addFlash();
});
});
I hope someone else will find this useful.
Its looking for the required module "jquery" before the config paths have loaded. So basically what require.js does it assume that "jquery" is a javascript file and tries to look for it in the same directory as your "data-main" (defined in your HTML header).
I don't know what the solution is for this particular situation as I am fighting the same battle, but this seems to be different to the way that the jquery.js creators intended their plugin to be used judging by the content of this page: Common Errors

Resources