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
Related
I'm trying to understand how to modularize the Backbone ToDo tutorial
Originally everything is inside the same file, but if I try to extract to another file:
var TodoView = Backbone.View.extend({
...
});
then this throws an error:
var view = new TodoView({model: todo});
**Uncaught TypeError: undefined is not a function**
It's probably due to a scope issue, but I don't know how to create a reference inside the $(function() so I can create this new object inside the main function.
Assuming that your first code part is TodoView.js,
and your second code part is app.js.
Write your html file like this,
<html>
<head>
<script type="text/javascript" src="js/TodoView.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body>
// your dom
</body>
</html>
(Edited, at 2015-07-27)
sorry for my late reply.
how about this?
<html>
<head></head>
<body>
<!-- your dom -->
<script type="text/javascript" src="js/TodoView.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
In many case, most javascript codes are appended to just before </body>, so that javascript can use your dom!
You can use something like require.js to load your external files and manage dependancies.
Ok, the solution was to move the script references to the end of the body instead of inside the head tags.
I think that the reason is that TodoView.js is making use of templates that were defined in the body, and since the js file was being loaded before the body, the templates were not yet available.
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();
});
};
How do we define different javascript files for different view pages in play framework??
One way is to=>
#main(title, """
#*JS CODE*#
"""{
//Template Codes
}
And in main template, use it like=>
#(title,stringJS){
<script>
#Html(stringJS)
</script>
}
But what if the JS code is to be used in not all pages but selected few, the dev can't copy the JS code in every relative view page.In my case all the javascripts are loaded on the footer, which is a seperate template.
How do we solve this problem??
Any help is appreciated, thank you!
It's described in the Common templates use cases doc , section : 'moreScripts and moreStyles equivalents'
In very short it works like this (view)
#moreScripts = {
<script type="text/javascript">alert("hello !");</script>
}
#moreStyles = {
<style>background: pink;</style>
}
#main("Title", moreScripts, moreStyles){
Html content here ...
}
and in main.scala.html start with:
#(title: String, moreScripts: Html = Html(""), moreStyles: Html = Html(""))(content: Html)
<!DOCTYPE html>
<html>
<head>
<title>#title</title>
<link rel="stylesheet" media="screen" href="#routes.Assets.at("stylesheets/main.css")">
#moreStyles
<script src="#routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
#moreScripts
</head>
<body>
#content
</body>
</html>
I came up with my solution,thanks to this Helpful SO post, what I did was:
#main(title, """
#*NO JS CODE, but declaration itself*#
<script src="/assets/javascripts/libs/main.js" type="text/javascript"></script>
<script src="#routes.Assets.at("javascripts/libs/main.js")" type="text/javascript"></script>//Doing this gives out errors, so I had to hardcode the "src" location
"""{
//Template Codes
}
If there is more efficient way to solve this issue, ideas are welcome, because hard-coding src isn't an efficient way of dealing with this issue, imo.
I know its been asked many times, I have looked at the answers and not sure where I am going wrong.
I have looked at the docs on Handlebarsjs and followed a tutorial and both times I am getting the same error.
<!DOCTYPE html>
<html>
<head>
<script src="handlebars-v1.3.0.js"></script>
<script src="jquery.min.js"></script>
<script src="test.js"></script>
</head>
<body>
<script id="header" type="text/x-handlebars-template">
div {{ headerTitle }} div
Today is {{weekDay}}
</script>
</body>
</html>
And this is my Javascript
var theData = {headerTitle:"name", weekDay:"monday"}
var theTemplateScript = $("#header").html();
var theTemplate = Handlebars.compile(theTemplateScript);
$(document.body).append(theTemplate(theData));
I keep on getting the following error and i am unsure why
Uncaught Error: You must pass a string or Handlebars AST to Handlebars.compile.
You passed undefined
You are running Handlebars.compile() before theTemplateScript is loaded into the DOM. Move your test.js down below the template script and you should be good to go.
Moving the scripts to the bottom of the page also worked for me.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script id="header" type="text/x-handlebars-template">
div {{ headerTitle }} div
Today is {{weekDay}}
</script>
<script src="handlebars-v1.3.0.js"></script>
<script src="jquery.min.js"></script>
<script src="test.js"></script>
</body>
</html>
As others have said, the problem is that you are running Handlebars.compile() before the TemplateScript is loaded into the DOM.
Putting your javascript calls in $(document).ready() you make sure all the html is loaded first.
var theData = {headerTitle:"name", weekDay:"monday"}
$(document).ready(function(){
var theData = {headerTitle:"name", weekDay:"monday"}
var theTemplateScript = $("#header").html();
var theTemplate = Handlebars.compile(theTemplateScript);
$(document.body).append(theTemplate(theData));
});
in my case i was trying to assign some value to more deeper steps therefore, i faced the error.
Before my code was
app.use(function (req, res, next) {
res.locals.partials.weather = {}; = getWeatherData();
next();
});
and the problem was
res.locals.partials.weather
after removing the layer partial my problem was gone.
and the final code is
app.use(function (req, res, next) {
res.locals.weather = getWeatherData();
next();
});
In my case I got the same error but the issue was a typo in the template script in the html page. I had 'prouct-template' should have been 'product-template':
<script id="prouct-template" type="text/x-handlebars-template">
...
</script>
Once I fixed the typo the error went away and page loaded ok.
A bit of modification is needed in JavaScript file. I had the same issue. In my code, I called "handlebars" from Views (following explanation is with respect to views).
Include following in initialize function(init) of View :
theTemplate = Handlebars.compile(theTemplateScript);
In render write the remaining code :
var theTemplate = Handlebars.compile(theTemplateScript);
$(document.body).append(theTemplate(theData));
The correct way is to precompile the Handler, Store in file and then assign it to theTemplate.
You're using Handlebars.compile() before the template script loads. One simple trick would do the work for you. Use the defer tag in your script so that the entire body loads before the script runs in your <head> tag.
<head>
<script src="" defer> </script>
</head>
A simple script tag inside the body tag doesn't seem to work. The alert doesn't get triggered in the code below:
<body>
<script type="text/javascript">
alert('Hello');
</script>
{{>main}}
</body>
Any idea why?
Edit:
Just tried it with a fresh meteor app, no alert tag still:
<head>
<title>test</title>
</head>
<body>
<script type="text/javascript">
alert('Hello');
</script>
{{> hello}}
</body>
<template name="hello">
<h1>Hello World!</h1>
{{greeting}}
<input type="button" value="Click" />
</template>
Weird thing is when I copy paste the source of the html, made a new html page, and the alert will work.
Edit3: I deployed this app here: http://alert-in-body-test.meteor.com/
Do you get an alert box?
This question is still relevant in the current version of Meteor (version 0.5.4) so I wanted to describe how to include script at the end of the body.
To execute javascript at the end of the body, register a Handlebars helper and put the relevant code there, like this:
In client.html:
<body>
{{renderPage}}
{{afterBody}}
</body>
...
In client.js:
if (typeof Handlebars !== 'undefined') {
Handlebars.registerHelper('afterBody', function(name, options) {
$('body').append('AFTER BODY');
});
}
(For a great description of why this is required, see Rahul's answer to a similar question here: https://stackoverflow.com/a/14002991/219238 )
Its working for me
in onrender call this jquery
$.getScript('yours url')
It should work.
I have just pasted this inside one of my projects and it worked.
Your {{>main}} is strange for me tough. Also make sure that <body> is inside <html> tag.
Meteor is constructing the entire DOM from Javascript by rendering your page as a template -- the 'source' for your page as seen by the browser is basically:
<script type="text/javascript" src="/5a8a37bef5095c69bcd3844caf3532e1ba6d49bf.js"></script>
I can't find a definitive page stating that embedding a script tag in a template like this won't cause it to be executed, but it definitely feels against the spirit of what the framework is trying to achieve.
If the point is to achieve a clean separation of your markup and logic then why put it in the template. A better solution would be to use the meteor.startup call
Instead of looking the rendered html at developer tools, try looking the real downloaded html.
You will find a (probably) empty tag, with tons of script tags inside the .
In other words, the body of your meteor application is not the body of the final html, it's just your main template.
Instead, this ton on scripts shipped by Meteor, will load your templates.
So, your code will not run, cause it's been placed there. It's like when you manipulate DOM (with jQuery, for exemple), placing a script tag in DOM, after it's loaded. This script tag will not run.