Marionette + i18n in templates - backbone.js

I want to do some basic i18n in my application
I loaded the i18n plugin (from require.js) to my Application and created a directory nls in which i have several files e.g. project.js
I set up the default location in main.js file like
config : {
i18n : {
locale : 'de-de'
}
}
I now want to use the files in my View / Template. Can somebody explain to me how this is done? The templates are setup in one template.js file
My View:
define(['marionette', 'templates', 'i18n!nls/project'], function (marionette, templates, msg) {
return marionette.CompositeView.extend({
template : templates.project
});
});
My template:
<div class="container">
<div class="well">
<h2>Projects</h2>
</div>
</div>
Can someone explain to me how to use the file in my View / Template? Thanks in advance!
EDIT:
I figured out the solution by some try&error. As i am loading the templates via the require.js tpl! plugin i dont need to compile them if i call them by require('tpl!templates/dashboard.tmpl'). I can simply pass the i18n file i loaded by 'i18n!nls/dashboard'. In Marionette the view are rendered by default, so i did this:
define(['marionette', 'templates', 'i18n!nls/dashboard'], function (Marionette, templates, msg) {
return Marionette.CompositeView.extend({
template : function () {
return templates.dashboard(msg);
},
initialize : function() {
}
});
});
The files for the i18n plugin are well explained here:
http://requirejs.org/docs/api.html#i18n
I had to do this step by step, first i missed the root, then i wondered why my german locale did not load, but i simply forgot to set de-de : true in the root file. Now everything is working like a charm

first you load the i18 file via require.js to your view.
I use the handlebars templates in this example.
define([
'marionette',
'handlebars',
'text!modules/tableModule/templates/myTmpl.html',
'i18n!nls/dashboard',
],
function(Marionette, Handlebars, tmpl, locals) { ...
then you compile and load your template with the i18 object.
var template = Handlebars.compile(tmpl);
this.template = template(locals.myVar);
you can go and do complex combinations as well
var template = Handlebars.compile(tmpl);
var data =_.extend(options, {lang:locals});
this.template = template(data);
your nls file will look like this
define({
"root": {
"myVar" : "some text in",
"canBeAnObjectTo": {
"title" : "my title ",
"contact" : "Contact",
}
and your view will be something like this:
<div class="cssClass">
<div class="table-caption pull-left">{{this.myVar}}</div>
</div>
hope that helps

Related

Simplest static rendering using backbone.js only for routing

I'm trying really hard to wrap my head around Backbone.js with Require.js and Handlebars.js. I'm still not 100% sure what the best combination is but this is what i'm currently using to redo the marketing site at work.
We've added some more pages and as it grows I thought it would be good to put the static site into an MV like Backbone.js. It seems that this would only be a good option if you have dynamic data as templates only seem suited for this typical scenario of looping through data and rendering the DOM elements.
But what if that's even too advanced for your needs and you just want to use the SOC and DRY practices of keeping your code in modules for easier maintenance and not having to put huge blocks of markup in your .html files.
But it seems like every tut just goes over the same telling of the backbone/require.js story. I'm assuming it's because no one uses backbone/require for static sites? I hope I'm wrong, don't people still have a need for something like backbone/require.js even for larger static sites just to make them easier to maintain? It seems like a logical solution.
I'm having the hardest time understanding how to link from one static page to another just using the Router file in Backbone.
Ideally I would like to have a header and footer template that are universal throughout the site and then just have large blocks of code for the content areas of each page, why is this so hard to accomplish with backbone/require and handlebars?
Can anyone give me a simple solution to what doesn't seem like a complicated problem so I don't have to create 17 static pages all repeating the same header and footer.
I think starting with a simpler project like this will help me understand more complicated examples later.
I have included a sample index.html, a sample view, a sample router, config file and app.js file so you can see how i'm trying to pull this together but no matter how I look at this it seems that the only feasible way is to create a bunch of static pages and link them through the Router. If at the end of the day that's all I could accomplish then I'm ok with that.
Thanks.
index.html:
<body>
<div id="container">
<!-- BODY WRAPPER -->
<section class="body-wrapper">
{{Header Template Here}}
{{Body Content Here}}
{{Footer Template Here}}
</section>
<!-- /.body-wrapper -->
</div>
<!-- /#container -->
<script data-main="js/config" src="js/libs/require.js"></script>
</body>
config.js:
// Set the require.js configuration for you application.
requirejs.config({
// Initialize the application with the main application file
baseUrl: 'js',
paths:
{
jquery : [
'//ajax.goolgleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
'libs/jquery.min'
],
modernizr : [
'//cdjns.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min',
'libs/modernizr'
],
hbs : '../bower_components/require-handlebars-plugin/hbs',
underscore : '../node_modules/underscore/underscore-min',
backbone : '../node_modules/backbone/backbone-min',
handlebars : '../node_modules/handlebars/handlebars',
text : '../node_modules/text/text'
},
hbs: {
helpers: true,
i18n: false,
templateExtensions: 'hbs',
partialsUrl: ''
},
shim: {
'jquery' : {
exports: '$'
},
'underscore': {
exports: '_'
},
'handlebars': {
exports: 'Handlebars'
}
}
});
// Launch the App
require(['app'],
function(App){
App.initialize();
});
app.js
define(
['jquery','underscore','backbone','router'],
function($, _, Backbone, Router){
var initialize = function() {
Router.initialize();
}
return {
initialize: initialize
};
});
router.js
define(
['jquery',
'underscore',
'backbone',
'views/HomeView',
'views/HeaderView',
'views/FooterView',
'models/FeatureModel',
'collections/FeatureCollection'],
function($, _, Backbone, HomeView, HeaderView, FooterView, FeatureModel, FeatureCollection){
var AppRouter = Backbone.Router.extend({
routes: {
'' : 'home', //#index
'/feature/:page' : 'featurePage',
'*actions' : 'defaultAction',
'about' : 'about', //#about
'/support' : 'support', //#support
}
});
var initialize = function(options) {
var appView = options.appView;
var router = new AppRouter(options);
router.on('home', function(){
var homeView = new HomeView();
homeView.render();
});
router.on('route:defaultAction', function(actions){
var homeView = new HomeView();
homeView.render();
});
router.on('support', function(){
var supportView = new SupportView();
supportView.render();
});
var headerView = new HeaderView();
var footerView = new FooterView();
Backbone.history.start();
};
return {
initialize: initialize
};
});
views/homeView.js
define(
['jquery','underscore','backbone' , 'text!/templates/home.html'],
function($, _, Backbone, homeTemplate){
var HomeView = Backbone.View.extend({
el : $('#content'),
render : function() {
this.$el.html(homeTemplate);
}
});
return HomeView;
});
templates/home.html
Big block of HTML content for the body of the index.html page
Few things:
Per http://backbonejs.org/#Router-routes the route callback should be in the form of route:(callback) so your home should be:
router.on('route:home', function(){});
You could also use
router.on('route', function(route, params){})
The router fires both events and you can handle as you wish. You can see the events documentation here: http://backbonejs.org/#Events-catalog
Also, not sure why you need handlebars or any templating language at all if they are all static html? You are already appending the html with your this.$el.html call.
If you just had simple html with:
<body>
<div id="header">
<div id="content">
<div id="footer">
</body>
Then you can stick your view el attribute like you have $('#header') etc and render accordingly.
Also not sure if you want to just have a single content view and swap out the html content in there instead on your render
routes: {
'feature/:page' : 'featurePage'
}
//route callback ex '/feature/feature1'
featurePage : function(page){
console.log(page) //'feature1'
//here you can create/render/set models/views accordingly
})}
Hopefully some of this helps.

how can I use external templates with Marionette Backbone

How exactly do I use an external template for my Marionette ItemView?
I read so many 'methods' I can't get any of them working...
JST Method ... I'm not on rails so can't use this
Backbone.Marionette.Renderer.render = (template, data) ->
path = JST["backbone/apps/" + template]
unless path
throw "Template #{template} not found!"
path(data)
RequireJS Method ... I'm not using require js
var tpl = require(inject[this.templateName]);
this.template = _.template(tpl);
What method should I be using?
I use Handlebars for my templating engine and hbs to retrieve the precompiled resource via require.js, that way all I have to do is define the template and set it as the ItemView's template; marionette does the rest.
Here's an example
View - welcome.js
define([
'app',
'jquery',
'backbone',
'marionette',
'hbs!templates/welcome'
],
function(App, $, Backbone, Marionette, template) {
return Backbone.Marionette.ItemView.extend({
template: template,
});
});
Template - welcome.html
<div>
<h1>Hello World</h1>
</div>
If you're not using handlebars, or can't use hbs, then something similar can be done with text.js - https://github.com/requirejs/text

Template not loading in a Backbone.js app - built using Yeoman

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.

Backbone.js separate templates from html file

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.

RequireJs text plugin doesn't appear to be loading template into DOM

I'm building an app with backbone/RequireJs on the front end and node/express on the backend. All written in CoffeeScript. I'm having trouble getting HTML template files to load properly with the text! plugin.
My Config is a s follows:
require.config
paths:
app: 'app'
jquery: 'libs/jquery-1.7.1'
jqueryTmpl: 'libs/jquery.tmpl'
jqueryUI: 'libs/jquery-ui-1.8.18.custom.min'
underscore: 'libs/underscore.amd'
order: 'libs/order'
backbone: 'libs/backbone.amd'
handlebars: 'libs/handlebars'
bootstrap: 'libs/bootstrap/js/bootstrap'
marionette: 'libs/backbone.marionette'
modelbinding: 'libs/backbone.modelbinding'
validation: 'libs/backbone.validation'
jqueryQtip: 'libs/jquery.qtip'
utils: 'utils'
jqueryDatatables: 'libs/datatables/jquery.dataTables'
DT_bootstrap: 'libs/datatables/DT_bootstrap'
user_maintenance: 'templates/tmpl.user.maintenance'
require [
"require",
"jquery",
"underscore",
"backbone",
"order!jqueryTmpl",
"order!marionette",
"order!validation",
"app"
]
This is the start of one of my views :-
define (require) ->
Backbone = require 'backbone'
Backbone.ModelBinding = require 'modelbinding'
require 'jqueryUI'
require 'jqueryQtip'
require '../../scripts/text!user_maintenance.html'
Utils = require '../../scripts/Utils.js'
class UserMaintenanceView extends Backbone.Marionette.ItemView
template: "#tmpl-user-maintenance"
className: "row"
.
.
.
If I look at the network tab in Chrome developer tools, the /scripts/templates/tmpl.user.maintenance.html file has been loaded via a GET. Clicking on it shows the contents that appear like so. (I removed the contents for brevity, its just HTML)
<script type="text/x-jquery-tmpl" id="tmpl-user-maintenance">
</script>
I don't get any script errors, but the template doesn't appear in the DOM and my view is not rendered. If I simply paste the HTML template into the main HTML file and don't try to load with the text plugin everything works fine. But I want to break my templates into separate files.
Any idea what I'm doing wrong?
The text!plugin does not inject the text into the DOM, it only loads the given file and it is up to you to process the content. See http://requirejs.org/docs/api.html#text for more information.
You'll have to assign/append the returned HTML from the template call into the DOM.
Example:
$('.someClass').html(Template, {}); // where {} === the data object for the template

Resources