undefined variable when rendering underscore template data in backbone - javascript

I am using backbone with underscore templates, but I'm having problem getting underscore to render the data I pass along to the template. Here's my code:
define([
'jquery',
'underscore',
'backbone',
'models/home/HomeModel',
'text!/app/templates/home/homeTemplate.html'
], function($, _, Backbone,HomeModel,homeTemplate){
var HomeView = Backbone.View.extend({
el: $("#page"),
initialize: function(){
var self = this;
self.model = new HomeModel();
},
render: function(){
var homeTitle = this.model.get('title');
var homeData = {
title: homeTitle
}
var compiledTemplate = _.template( homeTemplate, homeData );
this.$el.html(compiledTemplate);
}
});
return HomeView;
});
In this code, I can get all the way to the var homeData = {} object, which includes the proper title from the model, but when I create the compiledTemplate, I get an error saying title is not defined.
Any ideas what I'm doing wrong here?

From the Underscore.js documentation
var compiled = _.template("hello: <%= name %>");
compiled({name: 'moe'});
=> "hello: moe"
It looks like you are not using the _.template method correctly. It returns a compiled template function that you can call with the data to render:
var compiledTemplate = _.template( homeTemplate, homeData );
this.$el.html( compiledTemplate( homeData ) );

Related

Backbone Marionette - Log Model in Template

I am wondering how to log the model used in a Backbone.Marionette CompositeView's template?
The <% console.log(model) %> I am using causes an error Uncaught ReferenceError: model is not defined
Is there a way to log the content of the model from the template?
Here is a fiddle to my code: http://jsfiddle.net/16L1hen4/
Here is my Template and JavaScript
Template:
<div id="main"></div>
<script type="text/template" id="tree-template">
<li><%- name %></li>
<% //This console.log fails and I don't know why %>
<% console.log('inside template model =',model) %>
</script>
JavaScript:
var App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '#main'
});
var TreeModel = Backbone.Model.extend({
});
var TreeCollection = Backbone.Collection.extend({
model: TreeModel,
url: 'https://api.mongolab.com/api/1/databases/backbone-tree/collections/tree?apiKey=akey'
});
// Tree branch view
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
template: _.template( $('#tree-template').html() )
});
// Tree root view
var CollectionView = Backbone.Marionette.CollectionView.extend({
tagName: 'div',
className: 'js-tree-root',
childView: CompositeView,
});
var treeCollection = new TreeCollection();
treeCollection.fetch().done(function () {
var collectionView = new CollectionView({collection: treeCollection});
App.mainRegion.show(collectionView);
});
Edit: In a regular Backbone.View I can pass the model to the data as a property. Notice in this example that the View's model is passed to the template with a data property which can be logged in the template. This could be useful in the template to test for the existance of properties on the model. I am not sure how to do this using a Marionette CompositeView
var jsonData = {
"color": "red"
};
var TheModel = Backbone.Model.extend({
});
var TheView = Backbone.View.extend({
el: '#main',
tagName: 'ul',
template: _.template( $('#the-template').html() ),
render: function () {
var tmpl = this.template({data: this.model.toJSON()});
this.$el.html( tmpl );
}
});
var theModel = new TheModel(jsonData);
var theView = new TheView({model: theModel});
theView.render();
<div id="main"></div>
<script type="text/template" id="the-template">
<li><%- data.color %></li>
<% //Log the current model that the template uses %>
<% console.log('template model =',data) %>
</script>
This happens to be related to the anwser I posted on your question here : Backbone Marionette Composite View Rendering Template
and is cause by the same issue. model being undefined in the template context.
The data passed to your template is the following:
{_id: Object, name: "Level 1", children: Array[2]}
and model is undefined in this context.
If you want to log/control the data passed to your template you have should use SerializeData in such a way:
var CompositeView = Backbone.Marionette.CompositeView.extend({
tagName: 'ul',
serializeData: function(){
var data = Backbone.Marionette.CompositeView.prototype.serializeData.apply(this, arguments);
console.log(data);
return data;
},
template: _.template( $('#tree-template').html() )
});

Marionette: childViewContainer was not found

I am trying to learn how to use Marionette with Backbone. I am not sure why I am getting the following error: Uncaught ChildViewContainerMissingError: The specified "childViewContainer" was not found: ul
Here's a fiddle to my code: http://jsfiddle.net/e7L822c8/
Here is my JavaScript:
window.App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '.js-page'
});
App.start();
var TheModel = Backbone.Model.extend({});
var TheCollection = Backbone.Collection.extend({
model: TheModel,
});
var ListView = Backbone.Marionette.CompositeView.extend({
tagName: 'div',
className: 'js-list-container',
template: _.template( '#ListViewTemplate' ),
childViewContainer: 'ul',
childView: ItemView
});
var ItemView = Backbone.Marionette.ItemView.extend({
initialize: function() {
console.log('this.model =',this.model);
console.log(this);
},
tagName: 'li',
className: 'list-item',
template: _.template( '#ItemViewTemplate' )
});
var dataArray = [
{"name":"FirstObject"},{"name":"SecondObject"},{"name":"ThirdObject"}
];
var theCollection = new TheCollection(dataArray);
var listView = new ListView({collection: theCollection});
App.mainRegion.show(listView);
Here is my HTML:
<div class="js-page">
</div>
<script type="text/template" id="ListViewTemplate">
<h3>Here is a list</h3>
<ul class="js-list">
</ul>
</script>
<script type="text/template" id="ItemViewTemplate">
Display List Item here
</script>
There are two problems in the code :
you have to define ItemView before ListView in your js code
the js cant access the template in your code
template: _.template( '#ListViewTemplate' ),
if you replace ListViewTemplate by its content :
template: _.template( "<h3>Here is a list</h3><ul class='js-list'></ul>" ),
it works check the jsfiddle : http://jsfiddle.net/pwassqww/2/
so the problem is with your template definition .

Template with backbone.js

Having a simple template with backbone.js -
jsTemplateBackbone.html
<html>
<head>
<script src="jquery-2.1.0.min.js"></script>
<script src="json2.min.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<!--Order is important !!!-->
</head>
<body>
<script type="text/template" id="item-container">
<li><%= value %></li>
</script>
<script src="jsBackboneHomeView.js"></script>
</body>
</html>
jsBackboneHomeView.js
//Model
Wine = Backbone.Model.extend();
// Collection
Wines = Backbone.Collection.extend({
Model: Wine,
url: "#"
});
// Collection object
wines = new Wines([
{ name: "Robert Mondovi" },
{ name: "CakeBread" }
]);
// List
ListView = Backbone.View.extend({
tagName: 'ul',
initialize: function () {
// grabing the html template
this.template = _.template($('#item-container').html());
},
render: function () {
var el = this.$el, template = this.template;
el.empty();
wines.each(function (wine) {
el.append(template(wine.toJSON()));
});
return this;
}
});
// View
HomeView = Backbone.View.extend({
el: 'body',
initialize: function () {
this.render();
},
render: function () {
this.$el.empty();
this.$el.append("<h1>My App</h1>");
listView = new ListView();
// append two <li> on <ul> and return it
this.$el.append(this.listView.render().el);
return this;
}
});
// View instance
wineApp = new HomeView();
when I execute it , it gives an error -
Uncaught TypeError: Cannot call method 'replace' of undefined - underscore.js:1236
line 1236 - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
What is wrong here ?
(The code taken from this tutorial . )
The property in your model is called name while it is value in your template, and thus it can't be replaced. Try :
<li><%= name %></li>
in your template.
in your ListView render function, instead of returning this, return the values you want to be available as an object,
e.g.
return({
el: el
});

BackboneJS - Fetch data from PHP file and display in View

I'm fetching some data from my MySQL database with a php file and now I want to display this data in my View by passing it through a Model with the json_encode method. So far I created a Router, a Model, a Collection (is it necessary?) and a View. When i console.log the collection in my View, I can see that the data is actually there but my View shows nothing. When i console.log the Model I get the "undefined" message. So it seems that the Model is not instantiated, but I dont really know how to solve it. I use RequireJS and the HandlebarsJS for HTML templating purpose.
So here is my Router.
define(['backbone',
'views/firstpage',
'views/secondpage',
'views/thirdpage',
'collections/BandCollection']),
function( Backbone,FirstpageView, SecondpageView, ThirdpageView,BandCollection ) {
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'firstpage' : 'firstpage',
'secondpage' : 'secondpage',
'thirdpage' : 'thirdpage'
},
initialize: function () {
this.bandCollection = new BandCollection();
this.bandCollection.fetch({
error: function () {
console.log("error!!");
},
success: function (collection) {
console.log("no error");
}
});
},
thirdpage: function() {
var thirdpageView = new ThirdpageView({ el:'#topContent', collection:this.bandCollection}).render();
},
});
return Router;
}
);
My Model looks like this:
define([
"jquery",
"backbone"
],
function($, Backbone) {
var BandModel = Backbone.Model.extend({
url: "../metal/db/bands.php",
defaults: {
"id": '',
"band": '',
"label": ''
}
});
return BandModel;
});
My Collection:
define([
"backbone",
"models/BandModel"
],
function(Backbone, BandModel) {
var BandCollection = Backbone.Collection.extend({
model: BandModel,
url: "../metal/db/bands.php"
});
return BandCollection;
});
My HTML template:
<div>
<p><%= id %></p>
<p><%= band %></p>
<p><%= label %></p>
</div>
And My View looks like this:
define(['backbone','handlebars', 'text!templates/Thirdpage.html'],
function(Backbone,Handlebars, Template) {
'use strict';
var ThirdpageView = Backbone.View.extend({
template: Handlebars.compile(Template),
initialize: function () {
_.bindAll(this, 'render');
this.render();
},
render: function() {
console.log(this.collection);
this.$el.html(this.template(this.collection.toJSON()));
return this;
}
});
return ThirdpageView;
}
);
As said before, the console.log(this.collection) tells me that the data is available..
{length: 6, models: Array[6], _byId: Object, constructor: function, model: function…}
but console.log(this.model) gives me "undefined" - and the View actually displays the HTML mentioned before and not the data, meaning it actually shows
<div>
<p><%= id %></p>
<p><%= band %></p>
<p><%= label %></p>
</div>
So, can anyone help me out? I'm out of ideas...
Change your render() method in your view like this:
render: function() {
var self = this;
console.log(this.collection);
self.collection.each(function(model){
console.log(this.model); // can view all models here
self.$el.append(self.template({id:model.get('id'),band:model.get('band'),label:model.get('label')}));
});
return this;
}
Change your Template like this:
<div>
<p>{{id}}</p>
<p>{{band}}</p>
<p>{{label}}></p>
</div>

BackboneJS - Display JSON data

How do I pass JSON data through a Backbone Model to a view?
my model looks like this:
define([
"jquery",
"backbone"
],
function($, Backbone) {
var Model = Backbone.Model.extend({
url: "./bands.php",
defaults: {
"id": '',
"band": '',
"label": ''
}
});
return Model;
});
my View code looks like:
define(['backbone','handlebars', 'text!templates/bandpage.html'],
function(Backbone,Handlebars, Template) {
'use strict';
var BandpageView = Backbone.View.extend({
template: Handlebars.compile(Template),
initialize: function () {
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
return BandpageView;
}
);
and in my HTML template I have
<div>
<p><%= id %></p>
<p><%= band %></p>
<p><%= label %></p>
</div>
It doesnt show anything and I get the error "Cannot call method 'toJSON' of undefined"
what am I doing wrong?
Try this:
Update View initialize as:
initialize: function () {
this.listenTo(this.model, "change", this.render);
},
Create view instance as :
var view = new BandpageView({model: new Model()});

Categories