I am trying to build a quiz application using Node express and Handlebars as the templating engine.
I have the following template:
<div id="quiz">
<div class="container">
<div class="row" id="quiz-header-row">
<div>
<div id="question-title"></div>
</div>
</div>
<div class="row" id="quiz-choices-row">
<div id="choices"></div>
</div>
<div class="row" id="quiz-footer-row">
<button id="quiz-next-btn" class="btn btn-success">Next</button>
</div>
</div>
</div>
<!-- Template -->
<script id="choices-template" type="text/x-handlebars-template">
<div>\{{choices}}</div>
<div>
{{#each choices}}
{{this}}
{{/each}}
</div>
</script>
If I do not use the backslash before curly braces, handlebars displays an empty string and thus I cannot write this:
<div>{{choices}}</div>
Found on handlebars official website that I have to use: \{{choices}}.
The javascript that fills the template with data:
renderChoices: function() {
var template = Handlebars.compile($('#choices-template').html());
var context = {
// array of quiz item choices
choices: Quiz.questions[Quiz.currentIndex].choices
};
$('#choices').html(template(context));
},
The issue I am facing is the #each block that does not display anything. The backslash before {{#each choices}} cannot be used as in the example above because the server throws "server internal error: 500".
This is the console logged context:
console log
The fiddle below works as needed and does not need the backslashes
fiddle.
But the exact same code I run in my project using Node does not display anything written inside the #each block.
I have Handlebars both on the server (express-handlebars) and on the client. Considering the results, I am doing something the wrong way.
Thank you in advance.
EDIT: Fixed by precompiling the templates in external files and including them as scripts in the view.
Try something like this:
{{#each choices as |choice|}}
{{choice}}
{{/each}}
And make sure choices is populated as you expect.
i just tried to execute your code it's printing the data, i have used jquery-2.2.1 and handlebars 2.0.0
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<script id="address-template" type="text/x-handlebars-template">
<div>
{{#each choices}}
{{this}}
{{/each}}
</div>
</script>
<!--Your new content will be displayed in here-->
<div class="content-placeholder"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js">
</script>
<script>
$(function () {
// Grab the template script
var theTemplateScript = $("#address-template").html();
// Compile the template
var theTemplate = Handlebars.compile(theTemplateScript);
// Define our data object
var context={
choices: ["choice1","choice2","choice3"]
};
// Pass our data to the template
var theCompiledHtml = theTemplate(context);
// Add the compiled html to the page
$('.content-placeholder').html(theCompiledHtml);
});
</script>
</body>
</html>
Here is a link to plunker, i also tried with handlebars 4.0.3 and jquery 3.1.1 it's running fine.
Related
I have 2 HTML pages (page1.html and page2.html) and 1 data source. I'm able to display the handlebars data in page1.html by essentially making the entire page into a template
page1.html:
<body>
<div class="row" id="content-placeholder"></div>
<script id="some-template" type="text/x-handlebars-template">
<h1>{{Title}}</h1>
</script>
data.js
var source = $("#some-template").html();
var template = Handlebars.compile(source);
var gData = {
title: 'My Website'//,...
}
$("#content-placeholder").html(template(gData));
This works, but I'd like to display part of the same data object on the second html page.
page2.html
<body>
<div class="row" id="content-placeholder2"></div>
<script id="second-template" type="text/x-handlebars-template">
</script>
I tried using partials but I don't think that's the solution. How can I compile two templates?
Thanks!
Is there any way to load handlebars templates more simply? Seems like an easy thing to be able to do. If I have the following code for index.html:
<body>
<h1>From the index.html</h1>
<div id="hbs"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>
<script id="test" type="text/x-handlebars-template">
<h2>This is from HBS</h2>
<p>
hbs generated this p tag!
</p>
</script>
<script src="js/script.js"></script>
</body>
Here's the code for the script to compile the template in js/script.js:
var template = Handlebars.compile(document.querySelector("#test").innerHTML)
document.querySelector("#hbs").innerHTML = template({})
This works fine,but when I open the index.html I can see the header and p tag generated through the template. There has to be an easy way to abstract this template into a separate file!
You can put your template in a hbs file :
template.hbs:
<script type="text/x-handlebars-template">
<h2>This is from HBS</h2>
<p>
hbs generated this p tag!
</p>
</script>
And then use ajax to get your file instead of a querySelector to get your html
$document.ready(function(){
$.get( '/url/template.hbs', function( source ) {
var template = Handlebars.compile(source);
document.querySelector("#hbs").innerHTML = template({});
}
});
I'm playing around with Handlebars.js and trying to compile a small template. I am only using Handlebars.js and nothing more.
I am working locally on my computer, and not via any form of server.
my "html" looks like this. nothing special.
<!doctype html>
<html>
<head>
<script src="js/vendor/handlebars.min-4.0.4.js"></script>
</head>
<body>
<script id="menu-template" type="text/x-handlebars-template">
<h1>{{title}}</h1>
</script>
<section id="menu">
</section>
<script src="js/menu.js"></script>
</body>
</html>
And my JS is
var source = document.getElementById('menu-template').innerHTML;
var template = Handlebars.compile(source);
var data = {title: "test"};
document.getElementById('menu').innerHTML = template(data);
It seems that template() does not return anything, i don't get any result except what looks like a empty string.
And i have been playing around with this for a few hours and searching the internet for answers but no result.
Am i doing anything wrong here?
// Edit added the rest of the html page.
The code seems correct just make sure the Handlebars.js file is properly included before the existing script tag.
Ref for Handlebars CDN : https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.4/handlebars.js
I'm not sure if there has been a change in the way Meteor loads items, or the way it handles jquery, but I'm having an awful lot of trouble getting ckeditor to come up.
Main Template (Iron-router):
<template name="layout">
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
.....
</template>
Independent Editor Template:
<template name="editor">
<div class="editor_container">
<textarea class="editor"></textarea>
</div>
</template>
Ckeditor located at public/js/ckeditor, any time I try to do the Template.editor.rendered() technique, or even just trying to type $('.editor').ckeditor(); into the console, I get an error of:
$('.editor').ckeditor();
VM48825:2 Uncaught TypeError: undefined is not a function
Any ideas?
Try taking the <head> section out of the layout template. Reading here I believe the <head> section is treated specially be meteor (see: http://docs.meteor.com/#/full/structuringyourapp) and that it being inside a template may be causing the JS to actually not be loaded. Just a guess though.
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
<template name="layout">
.....
</template>
You can use IRLibLoader from iron:router into the onBeforeAction like this.
Router.route('/editor', {
name: 'editor',
template: 'layout',
onBeforeAction: function () {
var ckEditor = IRLibLoader.load('/js/ckeditor/ckeditor.js');
var adapter = IRLibLoader.load('/js/ckeditor/adapters/jquery.js');
if(ckEditor.ready() && adapter.ready()){
console.log('The 2 JS just finish load');
this.next(); // Render the editor page
if(Meteor.isClient){
Template.editor.rendered = function(){
$('.editor').ckeditor();
console.log("loading coeditor when template fully rendered");
}
}
}
}
});
Alternative on the main layout you can use this.
<head>
<script type="text/javascript" src="js/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="js/ckeditor/adapters/jquery.js"></script>
</head>
<template name="layout">
{{> yield}}
</template>
<template name="editor">
<div class="editor_container">
<textarea class="editor"></textarea>
</div>
</template>
And do the same rendered function
Template.editor.rendered = function(){
$('.editor').ckeditor();
//or make a little delay (1sec)
Meteor.setTiemout(function(){
$('.editor').ckeditor();
},100)
}
There are several problems with your code :
You can't put <head> sections inside another template, it must be done outside all templates.
The path to your JS files are broken, you must prepend a slash to them to reference files in the public directory.
Loading scripts in <head> sections is not a good idea because they will be loaded when your app first loads for every user, even if they never use the editor.
Here is a solution where we load every scripts asynchronously using jQuery promises when the editor template is rendered, and only then initialize the CKEditor.
Template.editor.rendered=function(){
var template=this;
$.when(
$.getScript("/js/ckeditor/ckeditor.js"),
$.getScript("/js/ckeditor/adapters/jquery.js")
).done(function(){
template.$(".editor").ckeditor();
});
};
I'm trying to use Ember in my grails project. However, I'm having a layout issue. The ember templates are always displaying below the footer. This does not happen with regular html, when I don't use Ember.
Here is my layout
<html>
<head>
<g:layoutHead/>
<r:require module="application"/>
</head>
<body>
<div id="wrap">
<g:layoutBody/>
<div id="push"></div>
</div>
<div id="footer>
</div>
</r:layoutResources/>
</body>
</html>
This is the page where I'm using ember template
<html>
<head>
<meta name="layout" content="main"/>
</head>
<body>
<script type="text/x-handlebars">
<h1>test</h1>
</script>
</body>
</html>
Here is my applicationresources.groovy
modules = {
application {
dependsOn "jquery", "emberjs","emberjsdata"
resource url:'js/application.js'
resource url:'js/App.js'
}
emberjs {
dependsOn 'jquery,handlebars'
resource url: 'js/ember-latest-stable.js'
}
handlebars {
resource url: 'js/handlebars-1.0.0-rc.4.js'
}
emberjsdata{
dependsOn 'emberjs'
resource url: 'js/ember-data-latest.js'
}
}
Problem
For some reason the hello shows up below the footer. Not sure why since it works fine with plain html
By default ember use the body as root element, then the contents of templates will be inserted and replaced in that element. So by default ember is a single page application.
If you need ember just for some piece of html, use by example:
Javacript
YourAppNamespace.rootElement = "#myEmberApp";
Html
<body>
<div id="wrap">
<!-- render normally contents from server -->
<g:layoutBody/>
</div>
<div id="myEmberApp">
<!-- all content here is controlled by ember -->
</div>
<div id="footer>
My company all rights reserved
</div>
</r:layoutResources/>
</body>
Hope it helps