Backbone.js template is not rendering data even though model passing data
View
var SectionView = Backbone.View.extend({
initialize : function() {
this.render();
},
model: Section,
className: 'div-body-row',
template: _.template($("#table-body-template").html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
Template:-
<script type="text/templete" id="table-body-template">
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= id %></div>
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= roomNumber %></div>
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= dateTime %></div>
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= personId %></div>
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= courseId %></div>
<div class="inner-div col-lg-2 col-md-2 col-sm-2 col-xs-2"><%= termId %></div>
</script>
this is entire code
var Section = Backbone.Model.extend({
defaults : {
id : '',
roomNumber : '',
dateTime : '',
person : '',
course : '',
term : ''
}
});
var SectionView = Backbone.View.extend({
initialize : function() {
this.render();
},
model: Section,
className: 'div-body-row',
template: _.template($('#table-body-template').html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
var a = this.model.get("id");
var b = this.model.get("sectionName");
var c = this.model.get("roomNumber");
var d = this.model.get("dateTime");
var e = this.model.get("person");
var f = this.model.get("course");
var g = this.model.get("term");
console.log(a,b,c,d,e,f,g);
return this;
}
});
var SectionCollection = Backbone.Collection.extend({
model: Section,
url: 'http://localhost:8080/student-faculty-attendance/section/sectionDetails'+'?id='+id,
});
var SectionCollectionView = Backbone.View.extend({
initialize : function(){
this.render();
},
tagName: 'div',
className: 'div-body',
singleSectionview: function(section){
var sectionView = new SectionView({model: section});
this.$el.append(sectionView.el);
},
render: function(){
this.collection.forEach(this.singleSectionview, this);
return this;
}
});
var section_collection = new SectionCollection();
var section_collection_view;
section_collection.fetch({
success: function(collection) {
console.log(collection);
if (collection.length) {
section_collection_view = new SectionCollectionView({collection: collection});
$("#table-body").append(section_collection_view.el);
} else {
console.log("Collection is empty!!");
}
}
And even template is generating but without data
<div id="table-body" class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="div-body">
<div class="div-body-row">
<div class="inner-div"></div>
<div class="inner-div"></div>
</div>
<div class="div-body-row">
<div class="inner-div"></div>
<div class="inner-div"></div>
</div>
<div class="div-body-row">
<div class="inner-div"></div>
<div class="inner-div"></div>
</div>
</div>
</div>
You have defined model: Section in the view constructor, where Section is probably a model constructor. This is usually done in a collection, and the collection later constructs model instances using the specified constructor. View does not do that.
Calling toJSON() directly on a model constructor will result in error
Uncaught TypeError: .toJSON is not a function
because toJSON is defined on the prototype of constructor to be shared with it's instances, not directly on the constructor.
You should do:
var SectionView = Backbone.View.extend({
model: new Section()
});
but in this case if there are multiple instances of this view, they will share same model, which is generally not desired. Ideally you should create a model instance per view instance, like:
var view = new SectionView({model: new Section() });
or
var SectionView = Backbone.View.extend({
initialize : function() {
this.model = new Section();
this.render();
},
Related
I'm trying to use backbone to show on a page the result from an API call, I would like to iterate over the collection and create one entry for every element of the collection within my html. It seems I'm missing something cause I see the template tag rendered but none of my items are there. What's the problem with my code?
here the html
<div class="form-group" id="main">
<% _.each(collection, function(car) { %>
<div class="form-group">
<input class="form-control" /><%= car.get("model") %>
</div>
<% }); %>
</div>
and here js
var CarView = Backbone.View.extend({
el: "#main",
template: _.template($("#main").html()),
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template({collection: [{id:1, model:"ford"}, {id:2,model:"kia"}]}));
return this;
}
});
var carView = new CarView();
here the fiddle: https://jsfiddle.net/e5hg6rzp/3/
First of all I suggest you to keep your template in <script type='text'/template> ... </script> tag. Secondly you are using .get() method inside your template on plain objects which are do not have this method. In your example you can access property through a . -
<div class="form-group">
<input class="form-control" /><%= car.model %>
</div>
Check this fiddle
If you want to use Backbone.Collection when you should create Car Collection and Car Model:
var data = [{
id: 1,
model: "ford"
}, {
id: 2,
model: "kia"
}];
var CarView = Backbone.View.extend({
el: "#main",
template: _.template($("#templ").html()),
initialize: function() {
this.render();
},
render: function() {
return this.$el.html(this.template(new CarCollection(data)))
}
});
var CarModel = Backbone.Model.extend({
defaults: {
id: '',
model: ''
}
})
var CarCollection = Backbone.Collection.extend({
model: CarModel
})
var carView = new CarView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>
<div class="container">
<div class="form-inline panel panel-default">
<div class="form-group" id="main">
</div>
</div>
</div>
<script type='text/template' id='templ'>
<% _.each(models, function(car) { %>
<div class="form-group">
<input class="form-control" />
<%= car.get('model') %>
</div>
<% }); %>
</script>
I am trying to build backbone.js application with twitter API.
the application that I am working on performs 3 tasks:1-returns the recent tweets on the user 's timeline, 2-returns the user profile 3- provides the ability to search in twitter. my problem is that I want the results of the search functionality to appear in the location of the tweets when the user clicks the search button. in my code there is view to display the tweets and another view to display the results of searching..how to put view in the place of another view on runtime. here is some of the code to explain the idea:
index.html :
<body>
<header role="banner">
<!—some code here-->
</header>
<div id="search" class="inner-search">
<form>
<label>Search for</label>
<input type="search" id="searchbox" style="width: 70%;"
autofocus="" placeholder="I'm looking for.."/>
<button id="searchbutton" style="width: 10%;">Go</button>
</form>
</div><!--search-view-->
<div class="inner-content">
<nav role="navigation">
<ul class="chapter-list">
………
</ul>
</nav>
<div role="main" class="main-content metrouicss">
<div id='timeline' class='timeline-view'>
<h3>Tweets </h3>
</div>
</div><!--main-->
<div role="right" class="right-content">
<h3>My Profile </h3>
<div id="profile" class="profile-view">
<!-- This would be the template -->
</div></div><!--right-->
</div> <!-- /.content-wrapper -->
<footer role="contentinfo">
<div class="inner-footer">
<p class="copyright">© Eva Hriekes, 2015. All rights
reserved.</p>
</div> <!-- /.inner-footer -->
</footer>
<!-- Template for profile -->
<script type="text/x-handlebars-template" id="profile-template">
<div class='tiles clearfix'>
<div class="tile double bg-color-orangeDark">
<div class="tile-content">
<img src="{{user.profile_image_url}}" class="place-left">
<h3 style="margin-bottom: 5px;">{{user.name}}</h3>
<p style="float:left;">{{user.description}}</p>
<div class="brand">
<div class="badge">{{user.followers_count}} Followers</div>
</div>
</div>
</div>
</div>
</script>
<!-- Template for timeline -->
<script type="text/x-handlebars-template" id="timeline-template">
<ul class='listview fluid'>
{{#each tweet}}
<li >
<div class='icon'>
<img src='{{user.profile_image_url}}'></img>
</div>
<div class='data'>
<h4>{{user.name}}</h4>
<p>{{format text}}</p>
<p class="timestamp" style="text-decoration:underline;">
<i>{{friendlyDate}}</i></p>
<p style="font-weight:bold;">Rating:
<i class="fa fa-star-o"></i><i class="fa fa-star-
o"></i><i class="fa fa-star-o"></i><i class="fa fa-star-
o"></i><i class="fa fa-star-o"></i></p>
</div>
</li>
{{/each}}
</ul>
</script>
<!-- Template for search results -->
<script type="text/x-handlebars-template" id="search-template">
<ul class='listview fluid'>
{{#each tweet}}
<li >
<div class='icon'>
<img src='{{user.profile_image_url}}'></img>
</div>
<div class='data'>
<h4>{{user.name}}</h4>
<p>{{format text}}</p>
<p class="timestamp" style="text-decoration:underline;">
<i>{{friendlyDate}}</i></p>
</div>
</li>
{{/each}}
</ul>
</script>
<script data-main="js/main" src="js/vendor/require.js"></script>
</body>
</html>
timeline view:
define(['jquery', 'handlebars', 'backbone', 'app/collection
/Timeline','app/view/ProfilePopupView'],
function($, Handlebars, Backbone, Timeline,ProfilePopupView) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.TimelineView = Backbone.View.extend({
el: '#timeline',
template: Handlebars.compile($("#timeline-template").html()),
timeline: null,
events: {
'click .profile': 'showDialog'
},
initialize: function(options){
var self = this;
//create a collection for this view to render
self.timeline = new Timeline();//new
com.apress.collection.Timeline();
//initial render
self.render();
//force the fetch to fire a reset event
self.timeline.fetch({reset:true
});
self.listenTo(self.timeline, 'reset', self.render);
},
render: function(){
var self = this;
if(self.timeline.models.length > 0){
var output = self.template({tweet: self.timeline.toJSON()});
self.$el.append(output);
}
return self;
},
showDialog: function(options){
var self =this,
$target = $(options.currentTarget),
username = $target.data('user');
/**
* Reuse the profile view
**/
var profileView = new ProfilePopupView({user: username});
}
});
// export stuff:
return com.apress.view.TimelineView;
});
search view:
define(['jquery', 'backbone'], function($, Backbone) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.SearchView = Backbone.View.extend({
el: '#search',
model: null,
events: {
'click #searchbutton': 'runSearch'
},
initialize: function(options){
var self = this;
self.model = options.model;
},
runSearch: function(e){
var self = this;
query = $('#searchbox').val();
e.preventDefault();
console.log('Run search against ' + query);
//force a reset
self.model.set('query', '', {silent: true});
self.model.set('query', query);
}
});
return com.apress.view.SearchView;
});
results view:
define(['jquery', 'backbone', 'handlebars','dialog'], function($,
Backbone, Handlebars,Dialog) {
var com = com || {};
com.apress = com.apress || {};
com.apress.view = com.apress.view || {};
com.apress.view.ResultsView = Backbone.View.extend({
el: '#results', /* or should be el="#timeline"???*/
model: null,
template: Handlebars.compile($("#search-template").html()),
initialize: function(options){
var self = this;
self.model = options.model;
self.model.fetch({
error: function(e){
self.model.trigger("app:error", {message: 'Error
retrieving timeline information'});
},
success: function(e){
self.model.trigger("app:success", {message: 'success
retrieving timeline information'});
}
});
self.listenTo(self.model,'change', self.render);
self.render();
},
render: function(){
console.log('Display now');
var self = this,
output = self.template({tweet: self.model.get('statuses')});
/* I want to delete this code and display the results
in the place of tweets*/
$.Dialog({
'title' : 'Search Results',
'content' : output,
'draggable' : true,
'overlay' : true,
'closeButton' : true,
'buttonsAlign': 'center',
'keepOpened' : true,
'position' : {
'zone' : 'left'
},
'buttons' : {
'OK' : {
'action': function(){}
}
}
});
}
});
return com.apress.view.ResultsView;
});
can anyone help me in doing what I want?
I have an issue in backbone, I want to render 100 rows of data from backend ( fetched by url) and show between of button element and pagination. I have created two templates, and have two views one for the whole page and the other for individual items. But when I fetch the data they do not go between the button and pagination div, all the 100 rows go under that. How can I put them in proper place? These are my templates:
the list template:
<div class="message-list-actions">
<div class="action">
<select>
<option value="0">Bulk Actions</option>
<option value="1">Delete</option>
<option value="2">Mark As Read</option>
</select>
<button class="grey">OK</button>
</div>
<div class="action">
<select>
<option value="0">All</option>
<option value="1">Unread Messages</option>
<option value="2">Read Messages</option>
</select>
<button class="grey">OK</button>
</div>
<div class="results right">
<form>
<label for="results">Results pr. page</label>
<select name="results">
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="500">500</option>
</select>
</form>
</div>
</div> <!-- message-list-actions -->
<div class="message-list">
<div class="message-list-header row">
<div class="left check">
<input type="checkbox" name="type"/>
<label for="type">CHECK ALL</label>
</div>
<div class="left date" >
<span class="sorter">Date</span>
</div>
<div class="large-9 columns" >
<span class="sorter">Message</span>
</div>
</div>
<section class="message-item row">
<div class="message-list"></div>
<div class="left check" >
<input type="checkbox" class="type">
</div>
<div class="left date" >
<div class="icon"></div>
</div>
<div class="large-9 columns" >
</div>
</section>
<section>
<ul class="pagination">
<li class="arrow unavailable">Previous</li>
<li class="current">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li class="unavailable">…</li>
<li>12</li>
<li>13</li>
<li class="arrow">Next</li>
</ul>
</section>
other template:
<div class="message-list">
<section class="message-item row">
<div class="left check" >
<input type="checkbox" class="type">
</div>
<div class="left date" >
<p><%= created !== undefined ? created : "not available" %></p>
<div class="icon"></div>
<div class="severity normal"><%= name %></div>
</div>
<div class="large-9 columns" >
<h4><%= title %></h4>
<p><%= id %></p>
</div>
<!-- Delete -->
</section>
</div> <!-- .main -->
//view for message:
define([
"jquery",
"underscore",
"backbone",
"js/collections/messagesCollection",
"js/models/messagesModel",
"text!templates/messageView.html",
"text!templates/messageList.html",
"text!templates/messageDetails.html"
], function($, _ , Backbone,
MessagesCollection,
MessagesModel,
UserEditTemplate, UserViewTemplate, UserSelfEditTemplate, ResetPasswordTemplate, ChangePasswordTemplate){
MessageViewTemplate, MessageListTemplate, MessageDetailsTemplate){
var MessageView = Backbone.View.extend({
tagName : "div",
messageViewTemplate : _.template(MessageViewTemplate),
messageDetailsTemplate : _.template(MessageDetailsTemplate),
template : _.template(MessageDetailsTemplate),
collection : MessagesCollection,
initialize : function(){
this.model.on("change", this.render, this);
this.model.on("update", this.render, this);
},
render : function(){
//this.$el.html(this.userTemplate(this.model.toJSON()));
this.$el.html(this.messageViewTemplate(this.model.toJSON()));
return this;
}
});
return MessageView;
});
View for list of message:
define([
"jquery",
"underscore",
"backbone",
"js/models/loggedInUserModel",
"js/models/currentTabModel",
"js/models/messagesModel",
"js/collections/messagesCollection",
"js/views/messageView",
"text!templates/messageList.html",
"text!templates/messageDetails.html",
"text!templates/header.html",
"text!templates/breadcrumbs.html",
"text!templates/footer.html"
], function($, _, Backbone,
MessagesModel,
MessagesCollection,
MessageView,
MessageListTemplate, MessageDetailsTemplate, HeaderTemplate, BreadCrumbTemplate, FooterTemplate
){
var MessagesView = Backbone.View.extend({
el : $("#maincontent"),
messageListTemplate : MessageListTemplate,
messageDetailsTemplate : _.template(MessageDetailsTemplate),
collection : MessagesCollection,
initialize : function(){
console.log("initialize messages");
this.collection = new MessagesCollection();
this.collection.on("add", this.renderMessage, this);
this.collection.on("reset", this.render, this);
this.collection.on("update", this.render, this);
if(this.options.selfEdit === false || _.isUndefined(this.options.selfEdit)){
this.start();
}
else{
console.log("options", this.options);
this.currentUserModel.fetch();
}
},
start : function(){
this.collection.fetch();
this.currentUserModel.fetch();
this.renderFooter();
},
render : function(){
this.$el.html(this.messageListTemplate);
_.each(this.collection.models, function(item){
this.renderMessage(item);
}, this);
},
renderMessage : function(item){
var messageView = new MessageView({
model : item
});
this.$el.append(messageView.render().el);
},
renderMessageDetails : function(item){
var messageView = new MessagesView({
model : item
});
this.$el.append(messageView.renderSelfView().el);
}
});
return MessagesView;
});
//Model
define([
"jquery",
"underscore",
"backbone"
], function($, _ , Backbone){
var MessagesModel = Backbone.Model.extend({
defaults : {
id : null,
created : null,
timestamp : null,
severity : null
},
parse : function(response){
response.id = response._id.$oid;
response.created = response.created.$date;
response.timestamp = response.timestamp.$date;
response.severity = response.severity;
return response;
},
clear : function(){
this.destroy();
this.view.remove();
},
// Convert regular JSON into MongoDB extended one.
toExtendedJSON: function() {
var attrs = this.attributes;
attrs = _.omit(attrs, ["created", "timestamp"]);
if (_.isUndefined(attrs.created)) {
// console.log("this", this["this.created"]);
attrs.created = { $date: this.get("created") };
}
if (_.isUndefined(attrs.timestamp)) {
attrs.timestamp = { $date: this.get("timestamp") };
}
console.dir(attrs);
return attrs;
},
// Substute toJSON method when performing synchronization.
sync : function(method, model, options) {
/*
* If we are performing an update we need to call the extendedJSON method
* By calling this, we guarantee that we comply to the MongoDB model.
* After applying that model, we then call Backbone .sync protoryp and then set the model.toJSON method
* back to its original definition.
*/
if(method === "update" && !model.isNew()){
var toJSON = this.toJSON;
this.toJSON = this.toExtendedJSON;
var ret = Backbone.sync.apply(this, arguments);
this.toJSON = toJSON;
return ret;
}
else{
return Backbone.sync.call(this, method, this, options);
}
},
formatDate : function(dateString) {
return new Date(dateString).toUTCString();
}
});
return MessagesModel;
});
Collection
define([
"jquery",
"underscore",
"backbone",
"js/models/messagesModel"
],function($,_, Backbone, MessagesModel){
var MessagesCollection = Backbone.Collection.extend({
model : MessagesModel,
url : "/api/v1/message",
parse : function(response, xhr){
return response.list;
}
});
return MessagesCollection;
});
Try following for renderMessage():
renderMessage : function(item){
var messageView = new MessageView({
model : item
});
this.$el.find('div.message-list').append(messageView.render().el);
},
Also update the code in a similar way for renderMessageDetails().
I'm working with Backbone and for some reason I can't seem to show anything with the reset event. The stranger part is that when I trigger the add event it shows all my collection.
I'm using version 0.9.2 of Backbone:
Here's the code:
var TodoView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#item-template').html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
return this; // enable chained calls
}
});
var CoursesPageView = Backbone.View.extend({
el: '.page',
initialize: function () {
this.input = this.$('#new-todo');
todoList.on('add', this.addAll2, this);
todoList.on('reset', this.addAll, this);
console.log("getting ready to fetch localstorage");
todoList.fetch(); // Loads list from local storage
// Also triggers reset event
},
render: function(){
console.log("function: render2");
var template = _.template($("#courses").html(),{});
this.$el.html(template);
},
events: {
'keypress #new-todo': 'createTodoOnEnter'
},
createTodoOnEnter: function(e){
if ( e.which !== 13) { // ENTER_KEY = 13
return;
}
console.log("function: createOnEnter");
todoList.create({title: $('#new-todo').val()}); // triggers add event
console.log("passed to localstorage: " + $('#new-todo').val());
$('#new-todo').val(''); // cleans input box once enter is pressed
},
addOne: function(todo){
var view = new TodoView({model: todo});
console.log("show li");
$('#todo-list').append(view.render().el);
},
addAll: function(){
console.log("reset event triggered");
this.$('#todo-list').html(''); // clean the todo list
todoList.each(this.addOne, this);
},
addAll2: function(){
console.log("add event triggered");
this.$('#todo-list').html(''); // clean the todo list
todoList.each(this.addOne, this);
},
});
and for the index.html file part:
<script type="text/template" id="courses">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<h4 align="center" style="color:white;">Courses</h4>
</div>
</div>
</div>
<div class="container">
Add Course
<input id="new-todo">
<section id="main">
<ul id="todo-list"></ul>
</section>
</div>
</script>
<script type="text/template" id="item-template">
<div class="view">
<label><%- title %></label>
</div>
</script>
I can't get this thing to add when i click the add button. I'm completely new to this.
JS code
function RecipeApp() {
var _Ingredient=Backbone.Model.extend(COOKBOOK.Domain.Ingredient),
_Ingredients = Backbone.Collection.extend({
model: _Ingredient
}),
_IngredientView = Backbone.View.extend({
tagName: "li",
initialize: function () {
this.model.bind("change", this.render, this);
},
render: function () {
var templateid = this.model.get('ViewID');
$(this.el).html(Mustache.to_html($("#"+templateid).html(),this));
}
}),
_AddView = Backbone.View.extend({
id:"divAddIngredient",
events: {
"click .btn": "create"
},
render: function () {
var tmpAddAnIngredient = $("#tmpMasterView").html(),
$submain = $("#submain");
$submain.html(Mustache.to_html(tmpAddAnIngredient, COOKBOOK.Domain));
},
initialize: function (ingredients) {
console.log("init enter");
this.render();
this._Ingredients = ingredients;
this._Ingredients.bind('add', this.add, this);
console.log("init leave");
},
//added functions
create: function () {
console.log("create");
var typename = this.$(".typeName").val(),
ingredient = _.detect(COOKBOOK.Domain.Ingredients, function (i) { i.TypeName === typename });
if (!!ingredient) {
this._Ingredients.create(ingredient);
}
},
add: function (ingredient) {
console.log('add');
var view = new _IngredientView(ingredient);
this.$("#divIngredients").append(view.render().el);
}
});
this.Ingredients = new _Ingredients();
this.AddView = new _AddView(this.Ingredients);
}
$(function () {
window.app = new RecipeApp();
//
});
And here is the mustache template
<script id="tmpTempDirectoryIngredient" type="text/html">
<div class="block-message">
<form>
<fieldset>
<legend>Create a Temporary Directory</legend>
<div class="clearfix">
<input type="text" name="DirectoryName" class="DirectoryName" />
</div>
</fieldset>
</form>
</div>
</script>
<script id="tmpMasterView" type="text/html">
<div class="block-message info" id="divAddIngredient">
<form>
<fieldset>
<legend>Add an Ingredient</legend>
<div class="clearfix">
<select class="typeName">
{{#Ingredients}}
<option value="{{TypeName}}">{{Name}}</option>
{{/Ingredients}}
</select>
</div>
<div class="clearfix">
<input type="button" class="btn primary" value="Add Ingredient" />
</div>
</fieldset>
</form>
</div>
<hr />
<div id="divIngredients">
</div>
</script>
it started working as soon as i explicitly set the el property of the _AddView to a tag that existed when the _AddView was created.
$(function(){
new Apps({el:$("body"),'records':[1,2,3,4,5]});
});
Here need to give el.
because of only after DOM is generating.....
The way you are passing Ingredients to the _AddView initialize, they will be accessible by this.options (see http://documentcloud.github.com/backbone/#View-constructor).
I think a better way is pass your ingredients collection into you _AddView like this:
this.AddView = new _AddView({collection: this.Ingredients});
Then within your definition of your view, always refer to this.collection instead of this._Ingredients. That is I think a more standard way to do it.