Simplest of backbone.js examples - javascript

I'm creating a bare bones backbone example to try to learn it and am having issues getting my view to render. I've based it on Thomas Davis's tutorial but looked at many of the other apps and tutorials available.
I'm changing Davis's tutorial not only because I want to add an input box, but also because based on the backbone docs I thought it needed less code and a different structure. Obviously because I can't get this to work, I don't know what's needed and what isn't.
My ultimate goal was to just add the names in li tags within ul#friends-list, although I don't think el: 'body' will help me there.
What am I doing wrong? Thanks for any help.
My html:
<!DOCTYPE HTML>
<html>
<head>
<title>Tut</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
</head>
<body>
<input type="text" placeholder="Enter friend's name" id="input" />
<button id="add-input">Add Friend</button>
<ul id="friends-list">
</ul>
<script type="text/javascript" src="test.js"></script>
</body>
</html>
My test.js
$(function() {
Friend = Backbone.Model.extend();
//Create my model
var friends = new Friend([ {name: 'Eddard Stark'}, {name: 'Robert Baratheon'} ]);
//Create new models to be used as examples
FriendList = Backbone.Collection.extend({
model: Friend
});
//Create my collection
var friendslist = new FriendList;
//Created to hold my friends model
FriendView = Backbone.View.extend({
tagName: 'li',
events: {
'click #add-input': 'getFriend',
},
initialize: function() {
_.bindAll(this, 'render');
},
getFriend: function() {
var friend_name = $('#input').val();
var friend_model = new Friend({name: friend_name});
},
render: function() {
console.log('rendered')
},
});
var view = new FriendView({el: 'body'});
});

You had some fundamental problems with your code to get the functionality that you required. I turned your code into a jsfiddle and you can see the working solution here.
http://jsfiddle.net/thomas/Yqk5A/
Code
<!DOCTYPE HTML>
<html>
<head>
<title>Tut</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
</head>
<body>
<input type="text" placeholder="Enter friend's name" id="input" />
<button id="add-input">Add Friend</button>
<ul id="friends-list">
</ul>
<script type="text/javascript" src="test.js"></script>
</body>
</html>
$(function() {
FriendList = Backbone.Collection.extend({
initialize: function(){
}
});
FriendView = Backbone.View.extend({
tagName: 'li',
events: {
'click #add-input': 'getFriend',
},
initialize: function() {
var thisView = this;
this.friendslist = new FriendList;
_.bindAll(this, 'render');
this.friendslist.bind("add", function( model ){
alert("hey");
thisView.render( model );
})
},
getFriend: function() {
var friend_name = $('#input').val();
this.friendslist.add( {name: friend_name} );
},
render: function( model ) {
$("#friends-list").append("<li>"+ model.get("name")+"</li>");
console.log('rendered')
},
});
var view = new FriendView({el: 'body'});
});
I noticed that you wanted as little code as possible so I left some things out that you don't need such as declaring an actual model. It might be easier if you use a collection like in the example instead.
Also I have just launched a new site containing Backbone tutorials which might help solve your problem.
BackboneTutorials.com

Related

Backbone.js primer customisation issues

I've been trying to get my first Backbone.js app up and running, following the Backbone.js primer here.
I've followed the example through and now I'm trying to customise it for my purposes which are to simply retrieve and read a JSON file from my server. I don't need to be able to change or delete any of the data.
I've set up my html as per the primer below:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Backbone.js Primer</title>
<script type="text/javascript" src="./node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./node_modules/underscore/underscore-min.js"></script>
<script type="text/javascript" src="./node_modules/backbone/backbone-min.js"></script>
<script type="text/javascript" src="./node_modules/moment/moment.js"></script>
<script type="text/javascript" src="./backbone.js"></script>
</head>
<body>
<div>
<h1>Transcripts Data</h1>
<div id="dailyTranscripts-app">
<ul class="dailyTranscripts-list"></ul>
</div>
</div>
</body>
</html>
I've then coded my backbone.js file as the primer describes below:
var yesterday = moment (new Date()).add(-1, 'days').format('YYYY-MM-DD')
var yesterdaysDataURL = 'https://mihndbotblob.blob.core.windows.net/mihndbot-transcripts/finalTranscripts/dailyTranscripts/' + yesterday + '.json'
// Model class for each transcript iten
var DailyTranscriptsModel = Backbone.Model.extend({
defaults: {
type: null,
MessageID: null,
MessageTime: null,
MessageChannel: null,
MessageSenderID: null,
MessageSenderName: null,
ConversationID: null,
MessageText: null,
MessageRecipientID: null,
QuickReplyDisplayText: null,
QuickReplyPayload: null,
Question: null,
Answer: null,
FollowUpPrompts: null
}
});
// Collection class for the DailyTransctipts list endpoint
var DailyTranscriptsCollection = Backbone.Collection.extend({
model: DailyTranscriptsModel,
url: yesterdaysDataURL
});
// View class for displaying each dailyTranscripts list item
var DailyTranscriptsListItemView = Backbone.View.extend({
tagName: 'li',
className: 'dailyTranscripts',
initialize: function () {
this.listenTo(this.model)
},
render: function () {
var html = '<b>Message ID: </b> ' + this.model.get('MessageID');
html += '<br><b>Message Time: </b>' + this.model.get('MessageTime');
this.$el.html(html);
return this;
}
});
// View class for rendering the list of all dailyTranscripts
var DailyTranscriptsListView = Backbone.View.extend({
el: '#dailyTranscripts-app',
initialize: function () {
this.listenTo(this.collection, 'sync', this.render);
},
render: function () {
var $list = this.$('ul.dailyTranscripts-list').empty();
this.collection.each(function (model) {
var item = new DailyTranscriptsListItemView({model: model});
$list.append(item.render().$el);
}, this);
return this;
}
});
// Create a new list collection, a list view, and then fetch list data:
var dailyTranscriptsList = new DailyTranscriptsCollection();
var dailyTranscriptsView = new DailyTranscriptsListView({collection: dailyTranscriptsList });
dailyTranscriptsList.fetch();
The major changes I've made to the code (apart from some customisations) are to remove the templates the primer uses to create the views (I couldn't get them working) and I've removed the Backbone CRUD elements as I only require my app to read data from the server, not update or delete it.
The issue I have is that whilst I'm pulling back the JSON file from the server, none of the data is rendering in the HTLM <div> as expected, it's just blank.
I know that Backbone.js is retrieving the data as when I add .then(function() {console.log(dailyTranscriptsList);}); to the final dailyTranscriptsList.fetch() call I can see the data in the browser console:
You need to wrap all of your backbone.js code within jQuery's .ready()
// backbone.js
$(document).ready(function () {
// all your backbone.js code here
})
This causes your js to run after the DOM is ready, so Backbone will know how to find the elements it needs in order for views to work.
You could also move <script type="text/javascript" src="./backbone.js"></script> to the end of the page, right before </body>

Backbone - View not rendering

I'm new to backbone and trying to make a book library app. While running this code, it is not showing the template.
This is my index.html
<html>
<head>
<title>Example</title>
</head>
<body>
<form>
Name:<input type='text' id='name'/><br>
Author:<input type='text' id='auth'/><br>
Keyword:<input type='text' id='keyword'/><br><br>
<button id="add">Add</button>
</form>
<div id='book_list'>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="http://documentcloud.github.io/backbone/backbone-min.js"></script>
<script src="script.js"></script>
<script id="bookTemplate" type="text/template">
<ul>
<li><%= name %></li>
<li><%= auth %></li>
<li><%= keyword %></li>
</ul>
<button class="delete">Delete</button>
</script>
</body>
</html>
This is script.js
$(function(){
var bookmodel = Backbone.Model.extend({
defaults: {
name:'temp',
auth:'meee',
keyword:'nonee'
},
});
var booklist = Backbone.Collection.extend({
model:bookmodel
});
var bookview= Backbone.View.extend({
tagName:'div',
className: 'bookContainer',
template: _.template( $('#bookTemplate').html()),
events:{
'click .delete':'deleteBook'
},
render : function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
},
deleteBook: function(){
this.model.destroy();
this.remove();
}
});
var library = Backbone.View.extend({
model: bookmodel,
initialize: function( initialBooks ) {
$el='#book_list';
var one=new bookmodel({name:'ankur 1',auth:'asdf 1',keyword:'asdfkasdf 1'});
var two=new bookmodel({name:'ankur 2',auth:'asdf 2',keyword:'asdfkasdf 2'});
var bookcoll= [one,two];
this.collection = new booklist(bookcoll);
this.render();
},
render:function(){
this.collection.each(function (item){
var k= new bookview({model:item});
this.$el.append(k.render().el);
},this);
},
});
var xyz= new library();
})
Also, when i'm trying to code like this:
var library = Backbone.View.extend({
model: bookmodel,
$el:'#book_list';
..... //rest of the code
)};
var xyz= new library();
Then,it is leading to : Uncaught TypeError: undefined is not a function, at line
var xyz= new library();
I ran your code and it seemed fine. I dont know exactly whats in script.js but try including your template above your script.js file. It probably can't find your template at the point it was running
I was able to recreate your error in jsfiddle by using their underscore library backbone loader. It wasn't an issue with your code. The following fiddle shows your same error:
http://jsfiddle.net/32tsA/
While this one works fine:
http://jsfiddle.net/BympL/
The issue was with how you had the fiddle set up in my estimation.
I did make some minor changes to fix up capitalization and some best practices with Backbone:
var Bookmodel = Backbone.Model.extend({
defaults: {
name:'temp',
auth:'meee',
keyword:'nonee'
}
});
var Booklist = Backbone.Collection.extend({
model: Bookmodel
});
var Bookview = Backbone.View.extend({
tagName:'div',
className: 'bookContainer',
template: _.template( $('#bookTemplate').html()),
events:{
'click .delete':'deleteBook'
},
render : function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
},
deleteBook: function(){
this.model.destroy();
this.remove();
}
});
var one=new Bookmodel({name:'ankur 1',auth:'asdf 1',keyword:'asdfkasdf 1'});
var two=new Bookmodel({name:'ankur 2',auth:'asdf 2',keyword:'asdfkasdf 2'});
var bookcoll = [one,two];
var mybooks = new Booklist(bookcoll);
var Library = Backbone.View.extend({
render:function(){
this.collection.each(function (item){
var k= new Bookview({model:item});
this.$el.append(k.render().el);
},this);
},
});
var xyz = new Library({collection: mybooks, el: "#book_list"});
xyz.render();
I named the classes with capital case, removed the initialization of the models from your view (views should be told their models not create their models), and abstracted the el declaration from the Library declaration (so you can reuse the view in a different place).

backbone collection. fetch() not rendering the view in mozilla

i am trying to learn backbone.js ( Backbone.js 1.0.0) this is my sample html page where iam using collection. fetch() method to get the collection,and it is displayed using view .i am getting result in
google chrome,but nothing is displayed in mozilla. i don't know the exact reason.
while i refere to backone site http://backbonejs.org/#Collection-fetch
it is qouted that :
Note that fetch should not be used to populate collections on page load — all models needed at load time should already be bootstrapped in to place. fetch is intended for lazily-loading models for interfaces that are not needed immediately: for example, documents with collections of notes that may be toggled open and closed.
is this is related with my issue?
this is my sample html page
<!DOCTYPE html>
<html>
<head>
<title>Backbone Application</title>
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/underscore.js" type="text/javascript"></script>
<script src="js/backbone.js" type="text/javascript"></script>
</head>
<body>
<div class="list"></div>
<script id="personTemplate" type="text/template">
<td> <strong><%= name %></strong></td>
<td>(<%= age %>) </td>
<td> <%= occupation %> </td>
</script>
<script type="text/javascript">
//Person Model
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest User',
age: 30,
occupation: 'worker'
}
});
// A List of People
var PeopleCollection = Backbone.Collection.extend({
model: Person,
initialize: function(){
alert("intialise")
},
url:'/RestFul/rest/members/info',
});
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'table',
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
this.$el.append(personView.render().el); // calling render method manually..
}, this);
return this; // returning this for chaining..
}
});
// The View for a Person
var PersonView = Backbone.View.extend({
tagName: 'tr',
template: _.template($('#personTemplate').html()),
////////// initialize function is gone from there. So we need to call render method manually now..
render: function(){
this.$el.html( this.template(this.model.toJSON()));
return this; // returning this from render method..
}
});
var peopleCollection = new PeopleCollection();
//peopleCollection.fetch();
peopleCollection.fetch({ success: function () { console.log("collection fetched"); } });
//peopleCollection.fetch({context:collection}).done(function() {
// console.log(this.length)
// })
//console.log(peopleCollection.toJSON())
alert(JSON.stringify(peopleCollection));
var peopleView = new PeopleView({ collection: peopleCollection });
$(document.body).append(peopleView.render().el); // adding people view in DOM
</script>
</body>
</html>
any help will be appreciated
Try with
var fetching = peopleCollection.fetch({ success: function () { console.log("collection fetched"); } });
$.when(fetching).done(function(){
var peopleView = new PeopleView({ collection: peopleCollection });
$(document.body).append(peopleView.render().el); // adding people view in DOM
});
var fetching = peopleCollection.fetch({ success: function () {
var peopleView = new PeopleView({ collection: peopleCollection });
$(document.body).append(peopleView.render().el);
} });
I think we can call the view render inside the success callback

Cannot get models to display attributes

I would like to know why this is not displaying the entries I created. I am struggling to find good simple tutorials that use Marionette so I took the angry cats tutorial found here (http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/) and tried to make something similar but even simpler so I could understand what is going on better. Any help would be appreciated.
Here is the Javascript, I am using Marionette.js
MyApp = new Backbone.Marionette.Application();
MyApp.addRegions({
listBox : "#listBox"
});
Entry = Backbone.Model.extend({
defaults: {
entry : "Blank"
},
});
EntryList = Backbone.Collection.extend({
model: Entry
});
EntryView = Backbone.Marionette.ItemView.extend({
template: "entry-template",
tagName: 'tr',
className: 'entry'
});
EntriesView = Backbone.Marionette.CompositeView.extend({
tagName: "table",
template: "#entries-template",
itemView: EntryView,
appendHtml: function(collectionView, itemView){
collectionView.$("tbody").append(itemView.el);
}
});
MyApp.addInitializer(function(options){
var entriesView = new EntriesView({
collection: options.ents
});
MyApp.listBox.show(entriesView);
});
$(document).ready(function(){
var ents = new EntryList([
new Entry({ entry: 'abc' }),
new Entry({ entry: 'def' }),
new Entry({ entry: 'ghi' })
]);
MyApp.start({entry: ents});
});
Here is the html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Simple Demo</title>
<link rel="stylesheet" href="assets/screen.css">
</head>
<body>
<div id = "listBox">
</div>
<script type="text/template" id="entries-template">
<thead>
<tr class='header'>
<th>Entry</th>
</tr>
</thead>
<tbody>
</tbody>
</script>
<script type="text/template" id="entry-template">
<td><%- entry %></td>
<td><button class="delete">Delete</button></td>
</script>
<script src="js/lib/jquery.js"></script>
<script src="js/lib/underscore.js"></script>
<script src="js/lib/backbone.js"></script>
<script src="js/lib/backbone.marionette.js"></script>
<script src="js/demo.js"></script>
</body>
</html>
It seems you're not using the right key in your options. You should have:
var entriesView = new EntriesView({
collection: options.entry
});
As a side note, my "angry cats" tutorial is a bit dated. To learn the basics about using Marionette views, you'll be better off reading this free pdf: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf (it's the free sample to my Marionette book)
In addition your template selector isn't valid: you need to have "#entry-template" where you have "entry-template".

Event binding with views and AJAX-loaded collections

I'm starting out with Backbone.JS, and have a question about how this should work.
I have a page which should load a list of sports, and then render the view. Now, because the list of sports is loaded via AJAX, I need to bind events to the collection so that it's only rendered when the data from that collection is actually loaded.
Here's what I've got so far:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Test</title>
<script src="../../src/vendor/zepto.js" type="text/javascript" charset="utf-8"></script>
<script src="../../src/vendor/underscore.js" type="text/javascript" charset="utf-8"></script>
<script src="../../src/vendor/backbone.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="sportsList"></div>
<script type="text/template" id="sports-template">
<ul>
<% _.each(sports, function(sport){ %>
<li>
<%= sport.getDescription() %>
</li>
<% }); %>
</ul>
</script>
<script type="text/javascript" charset="utf-8" src="application.js"></script>
</body>
</html>
As for the javascript code:
var Sport = Backbone.Model.extend({
getDescription: function() {
return this.get('description');
}
});
var Sports = Backbone.Collection.extend({
model: Sport,
initialize: function(options) {
this.bind("refresh", function() {
options.view.render();
});
var sports = this;
$.ajax({
url: 'http://localhost:8080/?service=ListSportsService&callback=?',
dataType: 'jsonp',
success: function(data) {
sports.refresh(data);
}
});
}
});
var SportsView = Backbone.View.extend({
el: '#sportsList',
template: _.template($('#sports-template').html()),
initialize: function() {
this.model = new Sports({view: this});
},
render: function() {
$(this.el).html(this.template({sports: this.model.models}));
return this;
}
});
var SportsController = Backbone.Controller.extend({
routes: {
'sports': 'listSports'
},
listSports: function() {
new SportsView();
}
});
$(document).ready(function(){
window.app = new SportsController();
Backbone.history.start();
});
The part that really nags me is having to pass the view to the collection and binding the refresh event there so that I can render the view once everything is loaded.
My question is, is there a DRYer/simpler way of doing this that I'm missing?
Keep in mind I'm using ZeptoJS instead of jQuery.
Your collection should read
var Sports = Backbone.Collection.extend({
model: Sport,
url: '/?service=ListSportsService&callback=?'
});
Always use Backbone.sync functionality when possible (here by specifying the url on the collection and using fetch).
Your controller should read
var SportsController = Backbone.Controller.extend({
routes: {
'sports': 'listSports'
},
listSports: function() {
//create the view with the collection as a model
this.sports = new Sports();
this.view = new SportsView({model: this.sports});
this.sports.bind("refresh", this.view.render);
// fetch all the sports
this.sports.fetch();
}
});
Enjoy.

Categories

Resources