I'm trying to link the template in my .jade view to my Backbone model, and it's just not displaying anything inside my template script.
My .jade view:
extends ../layout
block content
.page
script(type="text/template" id="createRecipeTemplate").
<div class="ingredients-pane">
<form id="ingredientForm">
*[form]*
</form>
*[etc.]*
</div>
script(src='/js/myBackboneFile.js')
myBackboneFile.js:
var Recipe = Backbone.Model.extend({
defaults: {*[defaults]*}
});
var Recipes = Backbone.Collection.extend({
url: '/api/recipes'
})
var recipes = new Recipes();
var RecipeView = Backbone.View.extend({
model: new Recipe(),
el: '.page',
initialize: function() {
this.template = _.template($('#createRecipeTemplate').html());
},
events: {
*[events]*
},
*[functions for my events]*,
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var RecipeView = new RecipeView();
Everything's linked up - if I type 'RecipeView' into the browser console, it gives me:
n {cid: "view2", $el: n.fn.init[1], el: div.page}
I've tried a few variations on the jade template syntax - putting pipes at the beginning of each line, using the dot after the script tag (as above), and just indenting normally (with the template in both standard HTML and Jade syntax each time), but no joy.
Am I missing something obvious?
Related
This question already has an answer here:
Backbone click event not firing in template View
(1 answer)
Closed 6 years ago.
I am getting the entire html code using jquery get() method and setting it on the el of backbone view.The view gets rendered perfectly but the click events i added are not firing. As i am a newbie to backbone i am not able to find the issue. Any help would be appreciated.
The currentTabID is contain the div id on which i want this html to be rendered.
view.js
var MyFirstView = Backbone.View.extend({
currentTabID:'',
initialize:function(){
this.render();
},
render: function (){
var self = this;
self.el = self.options.currentTabID;
$.get('resources/html/myBB.html', function(data) {
$(self.el).html(_.template(data));
});
return this;
},
events: {
'click .savebtnBB': 'invokeME'
},
invokeME: function (){
console.log('Fired');
}
});
Html looks something like below
myBB.html
<div id="sample_tab">
<div class="sub-main">
<form>
..
</form>
</div>
<div class="button">
<button class="savebtnBB">click me</button>
</div>
</div>
view.el is an actual dom element holding the event listeners for your view. You're replacing view's reference to that element with some number and appending the template to some other element.
Your view should act like an isolated unit as much as possible. Your code for appending it to something else should be outside the view, where you're creating it. Your code should look something like the following:
var MyFirstView = Backbone.View.extend({
initialize: function() {
var self = this;
$.get('resources/html/myBB.html', function(html) {
self.template = _.template(html);
this.render();
});
},
events: {
'click .savebtnBB': 'invokeME'
},
render: function() {
this.$el.html(this.template({ /*some data for template*/ }));
},
invokeME: function() {
console.log('Fired');
}
});
var viewInstance = new MyFirstView();
/*append to whatever you want*/
$(currentTabID).append(viewInstance.el);
I'm trying to setup a little app in backbone where I can add items to a list and, when I click them, they'll be deleted. I've managed to add items to the list but when using model.destroy() nothing happens.
When I console.log the click event on the list models I get:
child {cid: "c0", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object…}
for any item I click.
Code is below:
Html:
<h1>INDEX!</h1>
<form class="add-form">
<input type="text" name="name"/>
<hr />
<button type="submit" class="btn">Submit</button>
</form>
<h2>LIST STUFF</h2>
<ul class="blah">
{{#each indexCollection}}
<li class="li-class">{{name}}</li>
{{/each}}
</ul>
Javascript:
//Local Storage
App.Storage.Local = new Backbone.LocalStorage('localIndexList1-backbone');
//Index Model
App.Models.IndexModel = Backbone.Model.extend({
localStorage: App.Storage.Local,
defualts:{
name:''
},
urlRoot: '/'
});
//Index Collection
App.Collections.IndexCollection = Backbone.Collection.extend({
localStorage: App.Storage.Local,
model: App.Models.IndexModel,
initialize: function(){
console.log('Collection initialised');
},
url: '/'
});
//View for H1 and input form
App.Views.IndexView = Backbone.View.extend({
el: '.page',
events:{
'submit .add-form' : 'addNew',
'click' : 'deleteMe'
},
initialize: function(){
console.log('IndexView initialised');
},
addNew: function(ev){
// ev.preventDefault();
var submitEntry = $(ev.currentTarget).serializeObject();
var newEntry = new App.Models.IndexModel();
newEntry.save(submitEntry, {
success: function(newEntry){
// router.navigate('', {trigger: true});
console.log('SUCESSS!!!!!!!!!');
}
});
},
deleteMe: function(){
console.log(this.model);
//Whatever I put here will not work
}
});
//View for list
App.Views.ListView = Backbone.View.extend({
el: '.page',
initialize: function(){
console.log('ListView initialised');
},
template: Handlebars.compile($('#list').html()),
render: function(){
this.$el.html(this.template);
var that = this;
var indexCollection = new App.Collections.IndexCollection();
indexCollection.fetch({
success:function(indexCollection){
that.$el.html(that.template({indexCollection: indexCollection.toJSON()}));
}
});
}
});
Would anyone be able to help letting me know where I am going wrong?
Thanks!
Where are you creating one IndexView for each of your collection models? You should have an item view, configure its model to be one IndexModel, and move your delete code to that particular view. When you do that, you should also call remove in this item view.
This is why something like Backbone.Marionette helps a lot. Just throw in a CollectionView and you're done.
Think of it like this:
"list view" -> has a collection
"item view" -> has a single model
Anything you need to on the collection level (like adding a new one, re-loading, whatever), do it on your list view. Anything you need on model level (editing, saving, deleting), do it on your item view.
I want to do a simple application using backbonejs with mustache template. Can you give me a sample program??
New node file:
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest Worker',
}
});
var PersonView = Backbone.View.extend({
tagName: 'li',
initialize: function(){
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
};
this.render();
},
render: function(){
var template1 = _.template("Hello {{ name }}!");
this.$el.html( this.template1(this.model.toJSON()));
}
});
This is my js code.
Mustache template engine doesn't work this way. Here's a small example from the documentation :
var view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
// output will then contain processed html
var output = Mustache.render("{{title}} spends {{calc}}", view);
Anyway, i would recommend you using Handlebars (http://handlebarsjs.com/) instead of Mustache. It's almost the same syntax (and it has partials as Mustache does), but far more powerful thanks to its helpers.
Finally, you should use something to precompile your templates. You can either use handlebars's one (http://handlebarsjs.com/precompilation.html) or another one like Brunch, or Grunt.
[Edit] OK, let's try to elaborate a bit... I won't give you any complete example (i don't have one right now, and it wouldn't teach you anything), but the one i posted above should be sufficient to understand Mustache basics.
Now you have to find a way to precompile your templates, here's an answer with some clues : How to load templates with Hogan.JS from an external file?
While an underscore template is set like this in Backbone.js:
template: _.template(...)
A mustache template is set like this:
template: Mustache.render.bind(null,<template>)
//Mustache.render(template,view,[partials])
//a partial function is created because this.template should be a function
//<function>.bind() creates the partial function
don't do these:
template: Mustache.to_html(<template>) // deprecated
// or
template: Mustache.to_html.bind(null,<template>) // deprecated
// Use Mustache.render() and not Mustache.to_html()
I am learning Backbone/Handlebars/Require. I have looked all over online and on SO - are there any tutorials or websites that you can direct me to that would provide helpful information for using using handlebars instead of underscore?
Using handlebars.js instead of underscore templating is pretty straightforward. Check out this example:
https://cdnjs.com/libraries/backbone.js/tutorials/what-is-a-view
(scroll to the "Loading a Template" section)
SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
// Compile the template using underscore
var template = _.template( $("#search_template").html(), {} );
// Load the compiled HTML into the Backbone "el"
this.el.html( template );
}
});
Basically, the convention in backbone is to build your html in a render function. The use of templating engine is left completely up to you (which I like about Backbone). So you'd just change it to:
SearchView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function(){
// Compile the template using Handlebars
var template = Handlebars.compile( $("#search_template").html() );
// Load the compiled HTML into the Backbone "el"
this.el.html( template );
}
});
Since you're using require.js, you can make Handlebars a dependency at the top of your module. I'm pretty new to this, but it sounds like the learning to focus on would be Backbone.js patterns and require.js usage.
I would prefer to compile the template once (during initialize), that way you avoid to recompile the template with every render. Also, you need to pass the model to the compilated template in order to generate the HTML:
SearchView = Backbone.View.extend({
initialize: function(){
// Compile the template just once
this.template = Handlebars.compile($("#search_template").html());
this.render();
},
render: function(){
// Render the HTML from the template
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
If you are using require.js you wont be able to use the current Handlebars file. I used the following Handlebars Plugin and it seems to be kept up to date with the current version. Just replace your Handlebars file with the plugin above if Handlebars is returning null in your module.
define(["app", "handlebars",
"text!apps/templates/menu.tpl"
], function (app, Handlebars, template) {
return {
index: Marionette.ItemView.extend({
template: Handlebars.compile(template),
events: {
'click .admin-menu-ref': 'goToMenuItem'
},
goToMenuItem: function (e) {
//......
}
})
}
});
new view.index({model: models});
I can't get twitter bootstrap's modal to work with backbone.js.
The backbone view works fine.
window.CaseView = Backbone.View.extend({
tagName: "tr",
render: function() {
var that = this;
var tmpl = $("#tmplCase").render(that.model.toJSON());
$(that.el).html(tmpl);
return this;
},
events: {
"hover #pp-12444" : "open"
},
open: function() {
//console.dir(this);
$('#pp-12444').twipsy('show');
},
...
The twitter bootstrap js modules have been correctly loaded.
Try to initialize twipsy first and only then show it:
$('#pp-12444').twipsy({'placement': 'above'}).twipsy('show');
Did you make sure to include the necessary attributes on your #pp-1244 element? In the twipsy bootstrap demo, the text to display is set in the data-original-title attribute on the element.