Reputation: 1342
In the past, what I've been doing is when I want to render and display a collection with a template is just call the "each" method on the collection. And for each model, I make a new single view for each model and append it to the $el. But In this case this won't work. I have an input type text that is in my template and I don't want to display a new input for each model. I would rather somehow pass the collection to the template and iterate over the collection in the template. Also worth noting is that my collection is passed in through my main app view when in create a new instance of this view:
// clientsview.js
define(
[
'backbone',
'ClientView',
'Clients'
], function(Backbone, ClientView, Clients) {
ClientsView = Backbone.View.extend({
tagName: '#page',
template: _.template( $('#allClientsTemplate').html() ),
initialize: function() {
this.render();
},
render: function() {
// var that = this;
console.log('collection');
console.log(this.collection);// successfully returns collection
console.log('template');
console.log(this.template);// successfully returns template function
// This causes an error:
//Uncaught TypeError: Cannot call method 'toJSON' of undefined
var tmpl = this.template({ clients: this.collection.toJSON() });
return this;
}
});
return ClientsView;
});
my template in index.html
// index.html
<script id="allClientsTemplate" type="text/template">
// I do not want create an input for every single model
// but I need the input to be part of the view.
<input type="text" class="table-search" id="search" autocomplete="off" placeholder="Search Clients…">
<table class="table" id="tblData">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Status</th>
</tr>
</thead>
<tbody id="tblDataBody">
<% _.each(clients, function(client) { %>
<tr>
<td><a href=""><%- client.first_name %></a></td>
<td><a href=""><%- client.last_name %></a></td>
<td><a href=""><%- client.status %></a></td>
</tr>
<% }); %>
</tbody>
</script>
I'm instantiating my clients view from within my main app view:
define(
[
'jquery',
'underscore',
'backbone',
'AddClientView',
'ClientsView',
], function( $, _, Backbone, AddClientView, ClientsView ) {
AppView = Backbone.View.extend({
initialize: function() {
// var addClientView = new AddClientView({ collection: this.collection });
var clientsView = new ClientsView({ collection:this.collection });
}
});
return AppView;
});
And I'm instantiating my main app view from my initialize method:
define('App', [
'jquery',
'underscore',
'backbone',
'Router',
'bootstrap',
'Clients',
'AppView'
], function($, _, Backbone, Router, bootstrap, Clients, AppView) {
function initialize() {
// for custom global events
window.vent = _.extend( {}, Backbone.Events )
var app = new Router();
Backbone.history.start();
// probably more appropriate to do this in app view
var clients = new Clients;// Get collection of clients
clients.fetch().then( function() {// fetch client collection from db
new AppView({ collection: clients });
});
}
return {
initialize: initialize
};
});
My initialize method is being called from main.js:
// main.js
require.config({
shim: {
'underscore': {
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'bootstrap': {
deps: ['jquery'],
exports: 'bootstrap'
}
},
paths: {
'text' : 'lib/require/text',
'jquery' : 'lib/jquery/jquery-1.9.1',
'underscore' : 'lib/underscore/underscore',
'backbone' : 'lib/backbone/backbone',
'bootstrap' : 'lib/bootstrap/bootstrap',
'App' : 'app',
'Router' : 'router',
'AppView' : 'views/app/appview',
'Client' : 'models/clients/client',
'Clients' : 'collections/clients/clients',
'ClientView' : 'views/clients/clientview',
'ClientsView' : 'views/clients/clientsview',
'AddClientView' : 'views/clients/addclientview'
}
});
require(['App'], function(App) {
App.initialize();
});
I'm getting an error when I try this approach (Uncaught TypeError: Cannot call method 'toJSON' of undefined). How can I make this work?
Upvotes: 0
Views: 8662
Reputation: 5196
Your Backbone is correct. Your problem here is that you're not passing the data through the promise created by fetch when you instantiate your AppView:
your code:
clients.fetch().then( function() {// fetch client collection from db
new AppView({ collection: clients });
});
it should be:
clients.fetch().then( function(resp) {// fetch client collection from db
new AppView({ collection: resp.data });
});
Upvotes: 1
Reputation: 611
You have to instantiate your collection, add items to it, then instantiate the view and pass the collection to it:
var clients= new Clients();
clients.add({FirstName: 'Joe', LastName: 'Blow', Status: 'Active' });
var clientsView = new ClientsView({collection: clients});
You also need to change your template:
<% _.each(collection, function(client) { %>
<tr>
<td><a href=""><%- client.get('FirstName') %></a></td>
<td><a href=""><%- client.get('LastName') %></a></td>
<td><a href=""><%- client.get('Status') %></a></td>
</tr>
<% }); %>
Upvotes: 2