I am using an .ejs template in my view. But for some reason the view does not load the given template. It returns undefined. Here's the code:
sandplate2.applicationView = Backbone.View.extend({
el: 'div',
template: _.template($("appl.ejs").html()),
initialize: function(){
console.log("Application view initialize");
_.bindAll(this, "render");
this.render();
},
render: function(){
console.log("Application view rendering");
this.$el.html(this.template());
return this;
}
});
Do I have to configure something else in order to load a template?
I structured my app using Yeoman. I used the init and backbone generators.
FYI - The template I am trying to load is loaded in the index.html using a script element.
If you built it using Yeoman, take a look at app.js to see if you are using Backbone.LayoutManager. You might have to change the configuration there for EJS to work. By default, I think it should be expecting Underscore templates.
I'm using Handlebars and I updated my app.js to look like this:
Backbone.LayoutManager.configure({
manage: true,
paths: {
layout: "templates/layouts/",
template: "templates/"
},
fetch: function(path) {
path = path + ".html";
if (!JST[path]) {
$.ajax({ url: app.root + path, async: false }).then(function(contents) {
JST[path] = Handlebars.compile(contents);
});
}
return JST[path];
}
});
I also added Handlebars to the module's define() call, passing in 'Handlebars' as a reference. You might need to do something similar for EJS.
Please try with latest backbone genearator with yeoman 1.0beta.
We have made lot of improvements on it including Precompiling ejs templates. You don't want to worry about templates, yeoman will precompile and load it for you.
A sample generated code for input-view is provided below.
Todo.Views.InputView = Backbone.View.extend({
template: JST['app/scripts/templates/input.ejs'],
render: function(){
$(this.el).html(this.template());
}
});
Conventions aside, it looks like the problem is simply your jQuery lookup.
_.template($("appl.ejs")...
$('appl.ejs') isn't a valid DOM selector unless you have an element like this in your index.html
<appl class="ejs"></appl>
If you're trying to target your template with jQuery, give it an ID or something that jQuery can find like so:
<script type="text/template" id="appl">
<div></div><!-- template html here -->
</script>
// later...
$('#appl').html()
// will get your template html
However, as others have mentioned, in a yeoman and require.js workflow, you can ask require.js to fetch the template for you as text and throw it around as a variable before creating an underscore template.
Related
In my MEAN app, I use jade as my template engine. My problem is, when I call an angular directive, jade code is not working but html code is working. My code is given below:
index.jade
div(ng-repeat="num in addDir")
admin-collection
directive.js
var formDir = angular.module("formDirective", []);
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// call jade template url
templateUrl: '../_template/_formTemplate/_adminCollection.jade'
};
});
_adminCollection.jade
h1 from _adminCollection templateUrl
If I use jade format code in _adminCollection.jade, it just show a plain text, not text inside h1 tag
But following code is working:
directive.js
var formDir = angular.module("formDirective", []);
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// call jade template url
templateUrl: '../_template/_formTemplate/_adminCollection.html'
};
});
_adminCollection.html code::
<h1> from _adminCollection templateUrl </h1>
How can I solve this problem?
Jade is a template engine. Browser has only built-in html parser, so it does not understand what jade code means and treats it as plaintext.
To make it work you need to convert it to html. You can use some task manager to do it. Two most popular task managers for node.js are gulp and grunt. Each of them has a working jade plugin which you can use right away.
Jade is something like less - it must be convert to another format, because browser can't understand that. When you use less, you have to transform it to css. And if you use jade - to html.
If you use grunt, you should look on it: https://github.com/gruntjs/grunt-contrib-jade
Otherwise you can check if your IDE can transform jade to html. For example PhpStorm can do this in automatic way.
Then in your directives you should specify path to html template, no jade.
You can use following directory structure:
app/
src/
js/
less/
jade/
dist/
templates/ <-- here you can put your htmls
styles/ <-- and here put css
js/ <-- if you want, you can put this minimalized app.js
that will contain all of your project,
see grunt-contrib-uglify for more info
EDIT: here is really great article about grunt: http://anthonydel.com/my-personal-gruntfile-for-front-end-experiments/ There is much more then you need, but maybe it will help you
.... Or you can to use webpack to do the work.
then you can load the template like this:
angular.module('app').component('myComponent', {
bindings: {},
template: require('./mytemplate.jade')()
});
You can to note that I'm invoking the returned function.
Another option is to keep the HTML templates in your DOM, but hidden:
div(ng-non-bindable, style="display: none")
#adminCollectionTemplate
div(ng-repeat="num in addDir")
admin-collection
#anotherTemplate
//- Alternatively, pull in the template from another file
include ./_formTemplate/_adminCollection.jade
and then use jQuery to fetch the HTML out of the DOM, and give it to angular:
formDir.directive('adminCollection', function() {
return {
restrict: 'E',
transclude: true,
// fetch template from DOM
template: $('#adminCollectionTemplate').html()
};
});
This will just work, without any Ajax or any task runners. But it will clutter up the DOM with templates that could otherwise be hidden away in the JS. And it is an extra step to place every new template into that div.
ng-non-bindable is needed to tell Angular to leave the template elements alone (don't manipulate them or bind to them), until their clones are actually used by the directive.
Helllo, probably this is a common question, but I didn't find the appropriate answer.
I have an html file: header.html which contains a header which I want to display
Here is my Backbone.View
el: $(".header"),
initialize: function () {
this.render();
},
render: function () {
var template = _.template( $("#header_template").html(), {} );
this.$el.html( template );
},
When I put the code inside a java script template, it works:
<script type="text/template" id="header_template">
code of header.html goes here
</script>
But when I use it this way:
<script type="text/template" id="about_template" src="header.html"></script>
it stops working even though, the firebug sees the code inside a template.
Can someone tell me what my mistake is and how to solve it
A clean way to organize your templates is to create a subfolder tpl. Here you add all your .html files
Coenraets has a nice tutorial where he uses this approach together with a templateloader function.
You then load the templates in memory before bootstrapping your backbone application.
tpl.loadTemplates(['header', 'wine-details', 'wine-list-item'], function() {
app = new AppRouter();
Backbone.history.start();
});
Looks like Backbone.view, meteor and handlebars have overlap functionality when it comes to manipulating a section of the DOM. I looked at the ToDo app which is suppose to use Backbone, but in reality, they only use the Router.
Backbone views also deal with templates... but they sound so different from meteor templates. Besides, it looks like both backbone & meteor can update the ui on a model update.
ok, I am lost!? Who does what?
Is Backbone really useful for a Meteor App? Can Backbone & Handle bars coexist?
and if they can, in the Meteor context, how to wire a Backbone view to a handlebars template?
EDIT: found the todo-backbone example. it seems to confirm that you can go either:
meteor + backbone + underscore templates
or... meteor + handlebars
meteor+backbone+handlebars doesn't seem like a viable option...
Thank you
It's very easy and no more work than using the Underscore template. Here's an example .html file:
<template name="user_list">
<ul>
{{#each users}}
<li>{{name}}</li>
{{/each}}
</ul>
</template>
And here's an example .js file:
Users = new Meteor.collection("users");
if (Meteor.is_client) {
Template.user_list.users = function() {
return Users.find();
}
window.UserView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render');
},
template: function() {
Meteor.ui.render(function() {
return Template.user_list();
});
},
render: function() {
$(el).empty().append(this.template());
}
});
}
You can then use a Router or another View to manage when you want to display the UserView just like you would in any other Backbone.js app.
The key is to use the Meteor.ui.render or other Meteor.ui method to render the HTML so that it's reactive.
I am working on a Backbone.js application. We are using underscore.js templates to load the contents to the View. Currently we have all the templates inside the index.html file, so the size of the file is increasing. Can anyone help me to find a solution for separating these templates to other files? Thanks in advance.
EDIT
Recently I have visited the Backbone patterns and I found that we can use JST templates to create separate template files for each template. They explained that we can create a jst.js file to put all our template code:
// http://myapp.com/javascripts/jst.js
window.JST = {};
window.JST['person/contact'] = _.template(
"<div class='contact'><%= name %> ..."
);
window.JST['person/edit'] = _.template(
"<form method='post'><input type..."
);
<script src="http://myapp.com/javascripts/jst.js"></script>
Now all the templates are in the jst.js file. But if you have lots of templates and you want to move the templates to separate files you can create separate template files:
// http://myapp.com/javascripts/jst.js
window.JST = {};
//http://myapp.com/javascripts/contactPerson.template.js
window.JST['person/contact'] = _.template(
"<div class='contact'><%= name %> ..."
);
//http://myapp.com/javascripts/editPerson.template.js
window.JST['person/edit'] = _.template(
"<form method='post'><input type..."
);
<script src="http://myapp.com/javascripts/jst.js"></script>
<script src="http://myapp.com/javascripts/contactPerson.js"></script>
<script src="http://myapp.com/javascripts/editPerson.js"></script>
Please let me know if there is any simpler idea. Thanks!
You can have templates in seperate html files and can load them as text using requirejs. There is a plugin called text which will help you to do that.
Example:
define([
'text!templates/sampleTemplate.html'
], function(tmpl){
var Sampleview = Backbone.View.extend({
id: 'sample-page',
template: _.template(tmpl),
render: function() {
$(this.el).html(this.template());
return this;
}
});
return SampleView;
});
The html file "templates/sampleTemplate.html" will be taken from the root path specified in the require.js config
Load them via xhr. The lib requirejs (requirejs.org) loads html file dependencies this way. This will work when in development, but the templates should be compiled into the js files in production.
I've been messing around with a backbone.js app using require.js and a handlebars templates (I've added the AMD module stuff to handlebars) and just read that pre-compiling the templates can speed it up a fair bit.
I was wondering how I would go about including the precompiled templates with requirejs. I have a fair few templates to compile (upwards of 15), so i'm not sure if they should all be in the same output file or have their own once compiled. Also, from what it seems, the compiled templates share the same Handlebars namespace that the renderer script uses, so I'm not sure how I would go about that when requiring the templates in my files.
Any advice would be awesome!
A simple approach is to create a RequireJS plugin based on the existing text! plugin. This will load and compile the template. RequireJs will cache and reuse the compiled template.
the plugin code:
// hbtemplate.js plugin for requirejs / text.js
// it loads and compiles Handlebars templates
define(['handlebars'],
function (Handlebars) {
var loadResource = function (resourceName, parentRequire, callback, config) {
parentRequire([("text!" + resourceName)],
function (templateContent) {
var template = Handlebars.compile(templateContent);
callback(template);
}
);
};
return {
load: loadResource
};
});
configuration in main.js:
require.config({
paths: {
handlebars: 'libs/handlebars/handlebars',
hb: 'libs/require/hbtemplate',
}
});
usage in a backbone.marionette view:
define(['backbone', 'marionette',
'hb!templates/bronnen/bronnen.filter.html',
'hb!templates/bronnen/bronnen.layout.html'],
function (Backbone, Marionette, FilterTemplate, LayoutTemplate) {
...
In case you use the great Backbone.Marionette framework you can
override the default renderer so that it will bypass the builtin
template loader (for loading/compiling/caching):
Marionette.Renderer = {
render: function (template, data) {
return template(data);
}
};
Have a look at the Requirejs-Handlebarsjs plugin: https://github.com/SlexAxton/require-handlebars-plugin