I want to render collection in handlebars precompiled templates,
this.courses.fetch() is working
handlebars view is rendering correctly...(only each loop not rendering collection data)
here is my code...
router.js
App.Router = Backbone.Router.extend({
routes: {
'master/courses' : 'courses'
},
initialize: function(){
this.courses = new App.Collections.Courses();
this.list = new App.Views.List( {collection: this.courses} );
},
courses: function() {
$('#page').html(this.list.render().el);
}
});
var app = new App.Router();
Backbone.history.start();
courses.js
App.Collections.Courses = Backbone.Collection.extend({
model: App.Models.Course,
url: '/api/courses'
});
list.js
p.Views.List = Backbone.View.extend({
initialize: function() {
this.listenTo(this.collection, 'reset', this.render);
},
render:function(){
this.$el.html( Handlebars.templates.list(this.collection) );
return this;
}
});
list.handlebars
<h1>Courses</h1>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
{{#each models}}
<td>{{attributes.id}}</td>
<td>{{attributes.name}}</td>
{{/each}}
</tr>
</tbody>
</table>
this is my first attempt on backbone project kindly suggest good practice also
I don't see here the point where collection fetching is fired. The first line in your courses probably should be this.collection.fetch({ reset: true });
As I see in provided HTML structure, each should be before tr tag. Like this:
<h1>Courses</h1>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{{#each models}}
<tr>
<td>{{attributes.id}}</td>
<td>{{attributes.name}}</td>
</tr>
{{/each}}
</tbody>
</table>
Related
I wrote a table component:
<table ng-model="$ctrl.model" class="table" md-progress="promise">
<thead class="thead">
<tr>
<th class="theader">ID</th>
<th class="theader">A</th>
<th class="theader">Actions</th>
</tr>
</thead>
<tbody>
<tr md-row ng-repeat="row in $ctrl.data track by $index">
<td width="15%" class="trow">{{row.id}}</td>
<td width="15%" class="trow">{{row.a}}</td>
<td width="15%" class="trow">
<md-button ng-click="$ctrl.edit({x: row.id, y: row.a})"></md-button>
</td>
</tr>
</tbody>
I define the component as:
.component('tablesample', {
require: {},
templateUrl: 'Components/templates/tableSample.html',
bindings: {
data: '=',
model: '=',
edit: '&',
},
controller: function ($log) {
var tbl = this;
tbl.$onInit = function () {
};
tbl.$onChanges = function () {
};
}
})
I call the new component as:
<tablesample data="tableData" model="selectedRow" edit="editFunction()"></tablesample>
Edit Function is defined as:
$scope.editFunction = function(x,y){
console.clear();
$log.info(x);
$log.info(y);
};
The log statements always display 'undefined' and I don't know why, row.id is populated, if I dump it I can see 1,2,3, etc.... Inside editFunction I do an http get so if x is undefined the call will fail.
Can anyone see what I did wrong?
Thanks
D
I had to change:
<tablesample data="tableData" model="selectedRow" edit="editFunction()"></tablesample>
to:
<tablesample data="tableData" model="selectedRow" edit="editFunction(id,a)"></tablesample>
Thanks
Docmur
I looping through a collection in an attempt to add a row to a table on every loop. Here is the code that loops the collection, and build the single view,
App.Views.OrganisationMembersTab = Backbone.View.extend({
el: '#members',
template: _.template( $('#tpl-members-tab-panel').html() ),
events: {
},
initialize: function() {
this.$el.html( this.template() );
this.render();
},
render: function() {
this.addAll();
},
addAll: function() {
this.collection.each( this.addOne, this);
},
addOne: function(model) {
console.log(model);
var tableRow = new App.Views.OrganisationsMemberRow({
model: model
});
tableRow.render();
}
});
The single view that gets called to build the row looks like this,
App.Views.OrganisationsMemberRow = Backbone.View.extend({
el: '.members-list tbody',
template: _.template($('#tpl-organisation-member-row').html() ),
events: {
},
initialize: function() {
},
render: function() {
this.$el.prepend( this.template({
member: this.model.toJSON()
}));
return this;
}
});
The model that is being used once it has been parsed to JSON using toJSON() looks like this,
email: "john.doe#email.com"
first_name: "John"
last_name: "Doe"
The template for the row looks like this,
<script type="text/template" id="tpl-members-tab-panel">
<table class="table table-striped members-list">
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4"><button class="btn btn-success btn-sm pull-right">Add +</button></td>
</tr>
</tbody>
</table>
</script>
The above builds the main table components, and the next template is actually for a data row.
<script type="text/template" id="tpl-organisation-member-row">
<tr>
<td>#</td>
<td><%= first_name %> <%= last_name %></td>
<td>Admin <input type="checkbox" /></td>
<td>Remove</td>
</tr>
</script>
All I get output the the main table and then in the main tbody I get either nothing prepended or an empty <tr> why is this?
The problem is with your template which doesn't use member property, just use whole model instead.
You need replace
this.$el.prepend( this.template({
member: this.model.toJSON()
}));
with
this.$el.prepend( this.template(
this.model.toJSON()
));
working example
Your current implementation is a little confused. Your row view has no tagName so by default you'll be appending divs to your tbody.
The first thing I'd do is take the <tr> tag out of your tpl-organisation-member-row template and then alter your row view like so:
App.Views.OrganisationsMemberRow = Backbone.View.extend({
tagName: 'tr',
template: _.template($('#tpl-organisation-member-row').html() ),
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
Member row template:
<script type="text/template" id="tpl-organisation-member-row">
<td>#</td>
<td><%= first_name %> <%= last_name %></td>
<td>Admin <input type="checkbox" /></td>
<td>Remove</td>
</script>
Then I'd prefer to control appending the rows from your App.Views.OrganisationMembersTab view. So in your addOne method do the following:
addOne: function(){
var tableRow = new App.Views.OrganisationsMemberRow({
model: model
});
this.$('tbody').append(tableRow.render().el);
}
I have been trying to figure out how templates work along with models and collections. Parts of tutorials make sense, but other parts don't. So I have been messing in JSFiddle trying to get the following example to work.
All I really am trying to do is build a couple of objects. Then output them into a table in a specific div.
Based on the error it is almost as if the data isn't getting passed into the template. From my understanding what I am doing should work.
var Note = Backbone.Model.extend({
defaults : {
title: "",
description: ""
}
});
var note1 = new Note({title: "Patience", description: "Something we all need"});
var note2 = new Note({title: "Fun Times", description: "All the things"});
var Notebook = Backbone.Model.extend({
model: Note
});
notes = new Notebook([note1, note2]);
var NoteView = Backbone.View.extend({
el: '.content',
initialize: function() {
alert("hello");
this.render();
},
render: function () {
var template = _.template($('#notes-templates').html(), {notes: notes.models});
this.$el.html(template);
}
});
new NoteView();
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<div class="content">
</div>
<script type="text/template" id="notes-templates">
<table>
<thead>
<tr>
<th>title</th>
<th>scripture</th>
</tr>
</thead>
<tbody>
<% _.each(notes, function(note) { %>
<tr>
<td><%= note.get('title') %></td>
<td><%= note.get('description') %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
Try making Notebook a Backbone collection and using the collection api to iterate in the view. Also posted at http://jsfiddle.net/rossta/vn8hh5o7/2/
var Note = Backbone.Model.extend({
defaults : {
title: "",
description: ""
}
});
var note1 = new Note({title: "Patience", description: "Something we all need"});
var note2 = new Note({title: "Fun Times", description: "All the things"});
var Notebook = Backbone.Collection.extend({
model: Note
});
notes = new Notebook([note1, note2]);
var NoteView = Backbone.View.extend({
el: '.content',
initialize: function() {
alert("hello");
this.render();
},
render: function () {
var template = _.template($('#notes-templates').html(), {notes: notes});
this.$el.html(template);
}
});
new NoteView();
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<div class="content">
</div>
<script type="text/template" id="notes-templates">
<table>
<thead>
<tr>
<th>title</th>
<th>scripture</th>
</tr>
</thead>
<tbody>
<% notes.forEach(function(note) { %>
<tr>
<td><%= note.get('title') %></td>
<td><%= note.get('description') %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
I'm trying to implement an interface for a logger with EmberJS and has been great but I run into an wall.
Currently I have the following code:
logs.hbs
...
{{input action="search" onEvent="keypress" value=searchText class="search" placeholder="Search"}}
...
<table id="log" class="log">
<thead>
<th>Service</th>
<th>Start Time</th>
<th>End Time</th>
<th>URL</th>
<th>Method</th>
<th>User</th>
<th>Response Code</th>
</thead>
<tbody>
{{render "dashboard/logTableLine" model}}
</tbody>
</table>
...
logTableLine.hbs
{{#each model}}
{{#link-to "dashboard.log" _id tagName="tr"}}
<td>{{ServiceID}}</td>
<td>{{DateString StartTime}}</td>
<td>{{DateString EndTime}}</td>
<td>{{URL}}</td>
<td>{{Method}}</td>
<td>{{AuthName Auth}}</td>
<td>{{StatusCode}}</td>
{{/link-to}}
{{/each}}
and my app.js
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true
});
App.Router.map(function(){
this.resource("dashboard", { path: "/" }, function(){
this.route("logs", { path: "/logs" });
this.route("log", { path: "/logs/log/:_id" });
});
});
App.DashboardLogsRoute = Ember.Route.extend({
model: function(){
return Ember.$.getJSON("/logs.json");
},
actions: {
search: function(value){
if(value != '')
this.set("content", Ember.$.getJSON("/logs.json?search=" + value));
}
}
});
App.DashboardLogRoute = Ember.Route.extend({
model: function(params){
return Ember.$.getJSON("/logs/log/" + params._id + ".json");
}
});
My problem is binding that model to the view, so that after the search call to the server the view rerenders. I want to search all data, not only what I have in the interface (last 100 records).
So, first question: why the view isn't updating (binded) to the model?
Second: Is there a better way (best pratice) to do this?
Thanks in advance for any help.
Right now you're implementing search without triggering a re-route. So if the user searched and then wanted to go back to the page before they were at before they searched, they would have no way to do that. What you want to do is re-route the user to the same page, but pass in query parameters. Then in the model function you can see what parameters were passed in and fetch the data accordingly. Ember's latest and greatest way of doing this is the query-params feature: http://emberjs.com/guides/routing/query-params/ It's been in the works for a while and is now in beta. I'd give it a go, because it's a really clean, intuitive way of solving this problem. Good luck!
I just got started on using backbone.js. I have a view ListingListView that refreshes a table with new content when fetch() is called.
Problem: This table contains some <th> elements. If I were to do a $(this.el).empty(); and this.render() during the update of the table contents, the <th> elements will be removed. How can I prevent this? I want the <th> elements to remain. Thanks!
JS Code
// Views
window.ListingListView = Backbone.View.extend({
el: '#listing_list table',
initialize: function() {
this.model.bind('reset', this.refreshList, this);
this.model.bind('add', function(listing) {
$(this.el).append(new ListingListItemView({ model: listing }).render().el);
}, this);
},
render: function() {
_.each(this.model.models, function(listing) {
$(this.el).append(new ListingListItemView({ model: listing }).render().el);
}, this);
return this;
},
close: function() {
$(this.el).unbind();
$(this.el).empty();
},
refreshList: function() {
$(this.el).empty();
this.render();
}
});
HTML Code
<div id="listing_list">
<table class="table table-bordered table table-striped">
<th>Address</th>
<th>Beds</th>
<th>Baths</th>
<th>Price</th>
</table>
</div>
You could add some structure to your table, using thead and tbody:
<div id="listing_list">
<table class="table table-bordered table table-striped">
<thead>
<tr>
<th>Address</th>
<th>Beds</th>
<th>Baths</th>
<th>Price</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
And target the tbody in your render and refreshList functions:
render: function() {
var $tbody=this.$("tbody"); // or $(this.el).find("tbody")
_.each(this.model.models, function(listing) {
$tbody.append(new ListingListItemView({ model: listing }).render().el);
}, this);
return this;
},
refreshList: function() {
this.$("tbody").empty();
// or $(this.el).find("tbody").empty() if you prefer
this.render();
}
Notes:
don't forget you can use a collection as a special option instead of a model : http://backbonejs.org/#View-constructor It could be a bit clearer in the end.
Backbone proxies Underscore functions on collections, _.each(this.model.models... can be written as this.model.each (this.collection.each if you apply the note above)