Please see the following fiddle.
HTML
<script id="person" type="text/x-handlebars-template">
<div>Title : {{title}} </div>
<div>First Name : {{firstname}}</div>
<div>Last Name : {{lastname}}</div>
</script>
<div id="people"></div>
JS
(function ($) {
var personTemplate= Handlebars.compile($("#person").html());
var Person= Backbone.Model.extend({
title: null,
firstname : "",
lastname : ""
});
PersonView = Backbone.View.extend({
tagName: "div",
template: personTemplate,
render: function () {
$(this.el).html(this.template(this.model));
return this;
}
});
$(document).ready(function () {
var AppView = Backbone.View.extend({
initialize: function () {
var passView = new PersonView (
{ model: new Person({ title: "Mr",
firstname : "John",
lastname : "Smith"})
});
$('#people').append(passView.render().el.outerHTML);
}
});
var App = new AppView();
});
})(jQuery);
I've created a basic mode and view, but the parameters for the view are not being picked up by the template. If i set the value directly on the person model, it finds them. But not if i set them via a new instance of the mode (or even if I use the init methods to .set() them.
What am I doing wrong?
In order to get a object for use with your template you need to call your model's toJSON method.
For example
PersonView = Backbone.View.extend({
tagName: "div",
template: personTemplate,
render: function () {
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
If you inspect one of your models in Firebug (or just output it to the console) you'll notice that there are a lot more attributes then just the ones you specified, and that the values you specify are actually contained under a property attributes, calling toJSON returns an object with the models "values" that you specified.
Related
This should be simple but I've been stuck for about 3 hours on it, and can't seem to find a solution. I'm new to backbone so maybe I'm overlooking something.
I'm trying to render a view where the options all have values. It's coming out like this:
<select name="role" id="option-roles" class="form-control">
<option>All</option>
<option>Basic User</option>
<option>Basic Student</option>
...
</select>
But I want each option to have a value to look like this:
<option value='10'>Basic User</option>
In backbone my code looks like this.
app.RoleSelectView = Backbone.View.extend({
el: '#roles',
template: _.template($('#tmpl-roles').html()),
initialize: function() {
this.collection = new Backbone.Collection(app.mainView.results.roles, {
model: app.Role
});
this.render();
},
render: function() {
this.$el.html(this.template());
var frag = document.createDocumentFragment();
var view = new app.RoleOptionsView({
model: new app.Role(),
value: ''
});
frag.appendChild(view.render().el);
this.collection.each(function(role) {
var view = new app.RoleOptionsView({
model: role,
value: role.id.toString()
});
frag.appendChild(view.render().el);
}, this);
$('#option-roles').append(frag);
return this;
}
});
app.RoleOptionsView = Backbone.View.extend({
tagName: 'option',
template: _.template($('#tmpl-role-option').html()),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
Any help would be appreciated.
From the fine manual:
el view.el
[...]
this.el can be resolved from a DOM selector string or an Element; otherwise it will be created from the view's tagName, className, id and attributes properties.
If you want to add an attribute (such as value) to your el then use attributes:
app.RoleOptionsView = Backbone.View.extend({
tagName: 'option',
attributes: function() { // <---------------------------------
return {
value: 'where ever your value comes from'
};
},
template: _.template($('#tmpl-role-option').html()),
render: function() {
this.$el.html(this.template(this.model.toJSON());
return this;
}
});
Also, it is generally preferred that you say this.model.toJSON() rather than directly accessing this.model.attributes.
Like most data-ish things in views, the attributes can either be a static object or a function which returns an object. In your case, the attributes presumably depend on something in the view's model so a function is needed so that you can work with the view instance and its model.
I'm learning BackboneJS using a book called beginning backbone,
as far as I understood I can render my own el elements.
however when I call the render function it doesn't render anything on the page,
when I use console.log(view.el); it outputs what should be rendered so I guess its an issue with the render function.
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 0
}
});
var Library = Backbone.Collection.extend({
model: Book
});
var View = Backbone.View.extend({
initialize: function()
{
this.render();
},
render: function()
{
this.$el.html('Hello Library');
return this;
}
});
var book1 = new Book({title: "title1",author:"author1",pages: 11});
var book2 = new Book({title: "title2",author:"author2",pages: 2});
var library = new Library([book1,book2]);
var view = new View({
model: book1,
tagName: 'ul',
className: 'page',
attributes: {'data-date': new Date()}
});
Try this: http://jsfiddle.net/tonicboy/nWvRy/
The problem you had is that you specified tagName and className, which will render a detached node. You must then manually attach that node onto some place on the screen for it to appear. The other option (which I have done) is to specify an el attribute for an element already on the screen, then the view will be rendered (attached) to that pre-existing node. You can use el or tagName, className and attributes but not both.
HTML:
<div id="view-wrapper"></div>
JS:
var Book = Backbone.Model.extend({
defaults:
{
title: "default title",
author: "default author",
pages: 0
}
});
var Library = Backbone.Collection.extend({
model: Book
});
var View = Backbone.View.extend({
initialize: function()
{
this.render();
},
render: function()
{
this.$el.html('Hello Library');
return this;
}
});
var book1 = new Book({title: "title1",author:"author1",pages: 11});
var book2 = new Book({title: "title2",author:"author2",pages: 2});
var library = new Library([book1,book2]);
var view = new View({
model: book1,
el: '#view-wrapper',
attributes: {'data-date': new Date()}
});
UPDATE:
Here's another version which uses tagName, className and attributes. Notice how the view render() method has to attach it to an existing element.
http://jsfiddle.net/tonicboy/nWvRy/1/
<script id="entry-template" type="text/x-handlebars-template">
<h2>This is the template</h2>
{{ count }} items
</script>
<script type="text/javascript">
var MyNamespace = {};
$(document).ready(function () {
MyNamespace.Recipe = Backbone.View.extend({
tagName: "li",
render: function () {
return this.$el.text("Chicken Chilly");
}
})
MyNamespace.MyTagView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
var template = Handlebars.compile($("#entry-template").html());
this.$el.html(template);
return this;
},
count: 4
});
var View = new MyNamespace.MyTagView();
$("#content").html(View.el);
});
</script>
I get the output as 0 items , instead of 4 items
In this line:
template: template('entry-template'),
you are generating html of your compiled template and 'entry-template' context object (it's not an id, it's value object to your template). After generating that html you assign it to template property of MyNamespace.MyTagView
Later, in the render method, you are calling this template property (which is html) as it was a function:
this.$el.html(this.template(this));
but it is not a function, but a property containing generated html.
You should assign template like this:
template: template,
I am getting Uncaught ReferenceError: _auditNumber is not defined error while trying to bind my model to the view using backbone.js and underscore.js
<script id="searchTemplate" type="text/template">
<div class="span4">
<p>"<%= _auditNumber %>"</p>
</div>
<div class="span4">
<p>"<%= _aic %>"</p>
</script>
Collection
//Collection
var AuditsCollection = Backbone.Collection.extend({
initialize: function() {
this.on('add', this.render);
},
render: function() {
_.each(this.models, function (item) {
var _auditView = new AuditView({
model: item
});
$("#audits").append(_auditView.render().el);
});
},
});
Model
var Audit = Backbone.Model.extend({
url: function () {
return myUrl;
},
defaults: {
_auditNumber: "",
_aic: "",
},
parse: function (data) {
data.forEach(function (auditItem) {
var auditsCollection = new AuditsCollection();
auditsCollection.add(JSON.stringify(auditItem));
});
}
});
// Sub View
var AuditView = Backbone.View.extend({
className: 'row-fluid',
template: $("#searchTemplate").html(),
render: function () {
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
}
});
I know I am missing something simple, any help is appreciated.
2 problems (at least - you're kind of off in the weeds given how many backbone tutorials there are).
Your model URL is returning a list of results. That's what collections are for. Your model should fetch a single record and the parse method has to return the model's attribute data. If you stick with the tutorials, you won't need a custom url function and you won't need a custom parse function at all.
var Audit = Backbone.Model.extend({
url: function () {
//This needs to be a url like /audits/42 for a single record
return myUrl;
},
defaults: {
_auditNumber: "",
_aic: "",
},
parse: function (data) {
//this needs to return an object
return data[0];
}
});
You aren't passing a valid data object to your template function.
// Sub View
var AuditView = Backbone.View.extend({
className: 'row-fluid',
//compile template string into function once
template: _.template($("#searchTemplate").html()),
render: function () {
//render template into unique HTML each time
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
I am trying to understand the relationship between a model and a view. I've tried building a model and view to render that model.
I get the error Cannot call method 'toJSON' of undefined which I understand as the actual instance of the model is not being sent to the view.
I feel there is something missing in the initialize of the view?
The Model:
var sticky = Backbone.Model.extend({
defaults: {
title:"",
content:"",
created: new Date()
},
initialize: function() {
console.log("sticky created!");
}
});
The View:
var stickyView = Backbone.View.extend({
tagName:"div",
className:"sticky-container",
initialize: function() {
this.render();
console.log("stickyView created!");
},
render: function() {
$("#content-view").prepend(this.el);
var data = this.model.toJSON(); // Error: Cannot call method 'toJSON' of undefined
console.log(data);
var source = $("#sticky-template").html();
var template = Handlebars.compile(source);
$(this.el).html(template(data));
return this;
}
});
Creating new model and new instance of the view:
var Sticky = new sticky({title:"test"});
var StickyView = new stickyView();
You have to pass your model instance to your view, Backbone will do the rest:
constructor / initialize new View([options])
There are several special options that, if passed, will be attached directly to
the view: model, collection, el, id, className, tagName and
attributes.
which means you would create your view like this
var StickyView = new stickyView({model: Sticky});
And while you're at it, you could pass your compiled template and the DOM node you wish to set as your view element (and remove the tagName and className from your view definition) to avoid a strict coupling:
var stickyView = Backbone.View.extend({
initialize: function(opts) {
this.template = opts.template;
this.render();
console.log("stickyView created!");
},
render: function() {
var data = this.model.toJSON();
console.log(data);
this.$el.html(this.template(data));
return this;
}
});
var StickyView = new stickyView({
model: Sticky,
el: '#content-view',
template: Handlebars.compile($("#sticky-template").html())
});