I'd like to apologize for the mess below - having some difficulty with the following code. Attempting to display each model view through the collection view which while not succinct is required. Any help would be greatly appreciated. Tips and pointers as well. Thank you in advance.
$(function() {
/* Model */
var Publication = Backbone.Model.extend({
defaults: {
title: "",
published: ""
}
});
/* Collection */
var PublicationCollection = Backbone.Collection.extend({
model: Publication,
url: 'http://www.stellarbiotechnologies.com/media/press-releases/json'
});
/* Model View */
var PublicationView = Backbone.View.extend({
tagName: 'li',
className: 'publication',
el: 'displayHere',
template: _.template($('#publicationTemplate').html()),
initialize: function() {
this.model.on('destroy', this.remove, this);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
/* Collection View */
var AppView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
var pubs = this.collection;
pubs.fetch;
pubs.bind('reset', this.render);
pubs.bind('add', this.add, this);
pubs.bind('remove', this.remove, this);
},
render : function() {
this.collection.each(this.add, this);
return this;
},
add: function(pub) {
var pub = new PublicationView({model: Publication});
this.$el.html(pub.render().el);
},
remove: function(pub) {
var pubs = this.collection;
pubs.remove(pub);
pubs.render();
},
});
var App = new AppView({collection: PublicationCollection});
});
HTML:
<body>
<ul id="displayHere"></ul>
</body>
Template:
<script id="publicationTemplate" type="text/template">
<td class="id"><%= id %></td>
<td class="title"><%= title %></td>
<td class="published"><%= published %></td>
</script>
Here we go
!DOCTYPE html>
<html lang="EN">
<head>
<meta charset="UTF-8">
<title>Help 7</title>
</head>
<body>
<ul id="displayHere"></ul>
<script id="publicationTemplate" type="text/template">
<td class="title"><%= title %></td>
<td class="published"><%= published %></td>
</script>
<script src="js/jquery.js"></script>
<script src="js/underscore.js"></script>
<script src="js/backbone.js"></script>
<script>
$(function() {
/* The initialization of the models is correct, according to data json page you supply */
/* Model */
var Publication = Backbone.Model.extend({
defaults: {
title: "",
published: ""
}
});
/* They need to manipulate the data received since apparently come masked in the variable "news", this variable contains the main array with which it is going to work. */
/* Collection */
var PublicationCollection = Backbone.Collection.extend({
model: Publication,
url: 'http://www.stellarbiotechnologies.com/media/press-releases/json',
/*
for this we will use the "parse" function that provides us backbone, which performs this function is handled in the manner in which the data received before storing in the collection needed
*/
parse: function(response){
return response.news;
}
});
/*
Here you must not set the item as "#displayHere"
*/
/* Model View */
var PublicationView = Backbone.View.extend({
tagName: 'li',
className: 'publication',
template: _.template($('#publicationTemplate').html()),
initialize: function() {
this.model.on('destroy', this.remove, this);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
/* Collection View */
var AppView = Backbone.View.extend({
/*
this is where you establish your main item as "#displayHere"
*/
el: '#displayHere',
/*
Here is a somewhat tricky part when receiving data from somewhere, and it takes establish the way in which they will work and much depends on your project, then what we'll do is add a listener to the collection, this means that when you run the "fetch" this will execute the "sync" event which is to be this outstanding.
*/
initialize: function() {
this.listenTo(this.collection, "sync", this.render);
},
render : function() {
this.collection.each(this.add, this);
return this;
},
add: function(newModel) {
var pub = new PublicationView({model: newModel});
this.$el.append(pub.render().el);
},
/* Remove is not used until now */
remove: function(pub) {
var pubs = this.collection;
pubs.remove(pub);
pubs.render();
}
});
/*
First we have to create a collection, you can not just send the constructor PublicationCollection
*/
var AppPublicationCollection = new PublicationCollection();
/*
And created the collection, then we can send it
*/
var App = new AppView({collection: AppPublicationCollection});
/*
And finally we have to run the "fetch" function to send for data
*/
AppPublicationCollection.fetch();
});
</script>
</body>
</html>
Related
I am relatively new to Backbone.js and having difficulty rendering a subView. I have subViews in other parts of the app working properly, but I cant even render simple text in this one.
View:
Feeduni.Views.UnifeedShow = Backbone.View.extend({
template: JST['unifeeds/show'],
tagName: "section",
className: "unifeed-show",
render: function() {
var content = this.template({ unifeed: this.model });
this.$el.html(content);
var subView;
var that = this;
this.model.stories().each(function(stories) {
subView = new Feeduni.Views.StoriesShow({ model: stories });
that.subViews.push(subView);
that.$el.find(".show-content").append(subView.render().$el);
});
return this;
},
});
Subview:
Feeduni.Views.StoriesShow = Backbone.View.extend({
template: JST['stories/show'],
tagName: "div",
className: 'stories-show',
render: function() {
this.$el.text("Nothing shows up here");
return this;
},
});
Model:
Feeduni.Models.Unifeed = Backbone.Model.extend({
urlRoot: "/api/uninews",
stories: function() {
this._stories = this._stories || new Feeduni.Subsets.StoriesSub([], {
parentCollection: Feeduni.all_unifeeds
});
return this._stories;
},
});
The text "Nothing shows up here" should be displaying in the "show content" element, but all I get is this:
<section class="unifeed-show">
<article class="show-content">
</article>
</section>
Below is a slight modification of your code showing a working main view managing some sub-views.
var UnifeedShow = Backbone.View.extend({
// I've hard-coded the template here just for a sample
template: _.template("Feed: <%= feedName %><br/> <ul class='show-content'></ul>"),
className: "unifeed-show",
initialize: function () {
// Create an array to store our sub-views
this.subViews = [];
},
render: function () {
var content = this.template(this.model.toJSON());
this.$el.html(content);
var subView;
var that = this;
var subViewContent = this.$el.find(".show-content");
this.model.stories().each(function (story) {
var subView = new StoryShow({
model: story
});
this.subViews.push(subView);
subViewContent.append(subView.render().$el);
}, this);
return this;
}
});
var StoryShow = Backbone.View.extend({
tagName: 'li',
// This template will show the title
template: _.template('Title: <%= title %>'),
className: 'stories-show',
render: function () {
var content = this.template(this.model.toJSON());
this.$el.html(content);
return this;
},
});
var Unifeed = Backbone.Model.extend({
stories: function () {
// I'm just returning the value set on this model as a collection;
// You may need to do something different.
return new Backbone.Collection(this.get('stories'));
}
});
// ================================
// Code below is creating the model & view, then rendering
// ================================
// Create our model
var feed = new Unifeed();
// Put some data in the model so we have something to show
feed.set('feedName', 'A Sample Feed');
feed.set('stories', [{
title: "Story #1",
id: 1
}, {
title: "Story #2",
id: 5
}]);
// Create our main view
var mainView = new UnifeedShow({
model: feed,
el: $('#main')
});
// Render it, which should render the sub-views
mainView.render();
Here's a working JSFiddle:
https://jsfiddle.net/pwagener/7o9k5d6j/7/
Note that while this manual sort of sub-view management works OK, you'll be better off using something like a Marionette LayoutView to help manage parent and sub-views. It builds good best practices for this sort of thing without you needing to do it yourself.
Have fun!
The subview is named Feeduni.Views.StoriesShow but in your main view you are instantiating new Feeduni.Views.StoryShow. Name them consistently and see if you still have problems.
I've got a collection that does a url request,
class Movieseat.Collections.Moviesearch extends Backbone.Collection
url: ->
"http://api.themoviedb.org/3/search/movie?api_key=a8f7039633f2065942cd8a28d7cadad4&query=#{#query}"
setQuery: (q) ->
#query = q
return
I've got a view that renders a template, in the template is a input field. When text is typed in the input field the Collection gets updated with the value and when there's a keyup action in the input field the collection gets fetched.
class Movieseat.Views.Moviesearch extends Backbone.View
template: JST['movieseats/moviesearch']
el: '#moviesearch'
initialize: (opts) ->
{#collection} = opts
#render()
return
render: ->
$(#el).html(#template())
return
events:
"keyup input": "doSearch"
doSearch: (e) ->
inputtext = #$("form#autocomplete-remote input").val()
console.log inputtext
#collection.setQuery $(e.currentTarget).val()
#collection.fetch()
And now I'm trying to render each result in a li element, but I don't know how to do that. What would be the next step for me?
After a little play with your source code I came up with the following solution:
MoviesCollection = Backbone.Collection.extend({
url: function () {
return "http://api.themoviedb.org/3/search/movie?api_key=a8f7039633f2065942cd8a28d7cadad4&query=" + this.query;
},
setQuery: function (q) {
this.query = q;
},
parse: function (response) {
return response.results;
}
});
ResultsView = Backbone.View.extend({
initialize: function (opts) {
this.collection = opts.collection ;
this.collection.on('sync', this.render, this);
},
el: '#result-list',
template: _.template($("#results_template").html()),
render: function () {
var that = this;
this.$el.html(this.template({movies: this.collection.toJSON()}));
}
});
MoviesView = Backbone.View.extend({
initialize: function (opts) {
this.collection = opts.collection;
this.render();
},
pressDelay: 500,
el: "#search_container",
template: _.template($("#search_template").html()),
render: function(){
this.$el.html(this.template());
var resultsView = new ResultsView({collection: this.collection}) ;
resultsView.render();
},
events: {
'keyup input': 'doSearch'
},
doSearch: function (event) {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
this.timeoutId = setTimeout($.proxy(this.fetchValues, this), this.pressDelay);
},
fetchValues: function() {
// add check here for empty values, no need to fetch collection if input is empty
var inputtext = this.$el.find('input').val();
console.log (inputtext);
var that = this;
this.collection.setQuery(inputtext);
this.collection.fetch();
}
});
myCollection = new MoviesCollection();
var search_view = new MoviesView({
collection: myCollection
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.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>
<script type="text/template" id="results_template">
<ul id="search_container-results">
<% _.each(movies, function(movie) { %>
<li class="original_title"><%= movie.title %></li>
<% }); %>
</ul>
</script>
<div id="search_container"></div>
<script type="text/template" id="search_template">
<form id="autocomplete-remote">
<input type="text" id="search_input" value="Star" />
<input type="button" id="search_button" value="Search" />
</form>
<div id="result-list">
</div>
</script>
I have added timeout between input events, to increase queries frequency. You can configure it using pressDelay property of MoviesView.
Take a look at listenTo and the list of built in events.
I think you probably want to listen to the collection's events and call a render method when something changes.
For example, you could add this to your initialize to re-render when the collection is fetched:
this.listenTo(this.collection, 'sync', this.render);
Or you could just render a single item when it's added to the collection:
this.listenTo(this.collection, 'add', this.renderItem);
I've gotten my dropdown to be populate with lessons, but then I am stuck trying to figure out how I can get the text beneath my dropdown to change based on what the user selects by using Backbone.js
I am populating a select by adding options containing my Lessons and having the title show. Now I am just stuck on where should I insert the text so that it will change based on the selection.
Here is my HTML:
<script type="text/template" id="lesson-template">
<span class="lesson-title"><%= title %></span>
//How should I insert the text?
</script>
<script type="text/template" id="library-template">
<h1> Lesson Library </h1>
<select class="lessons"></select>
</script>
Here is my JSON file where I pull the information, I want to show the title now:
[{
"title": "Intro",
"text":"Do this now"
},
{
"title": "Second",
"text":"And then this"
}]
This is what is included in my javascript file:
window.Lesson = Backbone.Model.extend({});
window.Lessons = Backbone.Collection.extend({
model: Lesson,
url: './lessons.json'
});
window.library = new Lessons();
window.LessonView = Backbone.View.extend({
tagName: 'option',
className: 'lesson',
initialize: function() {
_.bindAll(this,'render');
this.model.bind('change',this.render);
this.template = _.template($('#lesson-template').html());
},
render: function() {
var renderedContent = this.template(this.model.toJSON());
$(this.el).html(renderedContent);
return this;
}
});
window.LibraryLessonView = LessonView.extend({
});
window.LibraryView = Backbone.View.extend({
tagName: 'section',
className: 'library',
initialize: function() {
_.bindAll(this, 'render');
this.template = _.template($('#library-template').html());
this.collection.bind('reset', this.render);
},
render: function() {
var $lessons,
collection = this.collection;
$(this.el).html(this.template({}));
$lessons = this.$('.lessons');
this.collection.each(function(lesson) {
var view = new LibraryLessonView({
model: lesson,
collection: collection
});
$lessons.append(view.render().el);
});
return this;
}
});
First give an id to each lesson.
window.LessonView = Backbone.View.extend({
...
render: function() {
var renderedContent = this.template(this.model.toJSON());
$(this.el).html(renderedContent);
// Then put the id as the option's value
$(this.el).val(this.model.get('id'));
return this;
}
...
});
window.LibraryView = Backbone.View.extend({
...
// bind the select's onchange event to this.onSelect
events: {
'change select': 'onSelect'
},
...
...
onSelect: function(e) {
// Grab the id of the select lesson
var lessonId = $(e.target).val();
// And get the lesson data back
var lesson = _.indexBy(this.collection.toJSON(), 'id')[lessonId];
// Then you could render you lesson view with something like this :
$('#target-container').html(
_.template($('#lesson-template').html(), lesson)
);
},
...
});
You could also go for a more elaborate views / collections construct but I'd suggest you get this working first.
I read all the topics on here about the argument but I can't understand what's with this code, is some hours I'm trying to get a sense of it:
It says "Uncaught Error: A "url" property or function must be specified" when I fire events save and remove from the TranslationView.
I tried to figure out other codes but even adding explicitly the url property to the collection it doesn't work... Thank You in advance
/**
* Translation Collection - The document
* -- Collection of all translations in a document
*/
var Document = Backbone.Collection.extend({
model: Translation,
localStorage: new Backbone.LocalStorage("translations-db")
});
var Docs = new Document;
/**
* Translation View
* -- A single language version
* This is a version of translation
*/
var TranslationView = Backbone.View.extend({
template: _.template('<div class="cnt-translation"><span class="delete-btn">delete</span><span class="save-btn">save</span> Language: <input value="english" /><textarea id="translation_0" class="translation"></textarea></div>'),
events: {
'click span.delete-btn': 'remove',
'click span.save-btn': 'save'
},
//'chnage ul#main-menu #add': 'addText'
initialize: function(){
_.bindAll(this, 'render', 'unrender', 'remove','save');
this.listenTo(this.model, 'destroy', this.remove);
},
render: function(counter){
this.$el.html(this.template(this.model.toJSON()));
return this;
},
unrender: function(){
$(this.el).remove();
},
remove: function(){
console.log(this.model);
this.model.destroy();
},
save: function(){
console.log(this.model);
this.model.save();
console.log(localStorage);
}
});
/**
* Translation Main View
* -- The Application
* This is the top level piece of the app
*/
var AppView = Backbone.View.extend({
el: $('#application'),
type: 'localStorage', // in future also "remoteStorage"
events: {
'click #add_trans': 'createOnEnter',
'click #save_trans': 'saveTranslations',
'click #remove_trans': 'removeTranslation'
},
initialize: function(){
_.bindAll(this,
'render',
'saveTranslations',
'addTranslation'
);
this.listenTo(Docs, 'add', this.addTranslation);
this.listenTo(Docs, 'all', this.render);
this.listenTo(Docs, 'reset', this.reloadAll);
this.render();
console.log('initialized and texts loaded');
Docs.fetch();
},
....
render: function(){
var self = this;
/*
_(this.collection.models).each(function(translation){
self.appendTranslation(translation);
}, this);
*/
}
addTranslation: function(){
console.log('addTrans called');
var translation = new Translation();
translation.set({
id: 'translation_' + Docs.length,
language: 'english' // modify item defaults
});
var translationView = new TranslationView({ model: translation });
$(this.el).append(translationView.render().el);
console.log(Docs);
},
createOnEnter: function(e) {
Docs.create({title: 'new trans'});
}
});
var ENTER_KEY = 13;
var app = new AppView();
console.log(app);
})(jQuery);
Your problem is that you try to save/destroy a model object which was never associated to your local storage backed collection.
The local-storage plugin first looks for the localStorage property on the model if it finds none it looks on the model's collection for the localStorage if still no localStorage found it fallbacks to the default Backbone.Sync behaior which needs an url so you get the exception.
And you have an unassisted model object because you create one in your addTranslation:
var translationView = new TranslationView({ model: translation });
But you don't need to this because this method called when an item added to your collection and you get the newly added item as a parameter.
You just need to change your method use the parameter translation instead of creating a new one.
addTranslation: function(translation){
translation.set({
id: 'translation_' + Docs.length,
language: 'english' // modify item defaults
});
var translationView = new TranslationView({ model: translation });
$(this.el).append(translationView.render().el);
},
i am trying to make my first backbone app, and have run into a problem that i just cant solve..
I have a list of links, each link has a counter next to it,
when i click on a link i want the counter to increment by 1. (i have made this, and it is working)
Next i want the link i clicked to move up in the list IF the counter value is higher than the link above.
like this.
first link (4)
second link (3)
third link (3) <-- if i click on this link i want it to move up above second link.
I have tried using comparator and sortBy, but each time i try something i just cant seem to re-render the view and also have the link move up one spot.
I did manage to sort the list initially, when the main view is initialized.
But updating the view and list placement after i click one of the links i cant figure out how to accomplish.
my code:
(function() {
window.App = {
Models: {},
Collections: {},
Views: {}
};
window.template = function(id) {
return _.template( $('#' + id).html() );
};
//Modellen
App.Models.Task = Backbone.Model.extend({
defaults: {
name: 'Foo Bar Baz',
uri: 'http://www.google.com',
counter: 0
},
validate: function(attr) {
if ( ! $.trim(attr.name) ) {
return 'En opgave kræver en title.';
};
}
});
//Collection
App.Collections.Tasks = Backbone.Collection.extend({
model: App.Models.Task,
comparator: function(task) {
return task.get('counter');
},
});
//Singel view
App.Views.TaskView = Backbone.View.extend({
tagName: 'li',
template: template('Tasks'),
initialize: function() {
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this);
},
events: {
'click .edit' : 'retTask',
'click .delete' : 'destroy',
'click .uriLink' : 'addCounter'
},
retTask: function() {
var newTaskNavn = prompt('Hvad skal det nye navn være', this.model.get('name'));
if ( !newTaskNavn ) return;
this.model.set('name', newTaskNavn);
},
destroy: function() {
this.model.destroy();
},
addCounter: function(e) {
e.preventDefault();
var newCounter = this.model.get('counter');
this.model.set('counter', newCounter + 1);
},
remove: function() {
this.$el.remove();
},
render: function() {
this.$el.html(this.template(this.model.toJSON()) );
return this;
}
});
//Collection View
App.Views.TasksView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('add', this.addOne, this);
this.render();
},
render: function() {
this.collection.each(this.addOne, this);
return this;
},
addOne: function(task) {
var taskView = new App.Views.TaskView({ model: task });
this.$el.append(taskView.render().el);
}
});
App.Views.AddTask = Backbone.View.extend({
el: '#addTask',
initialize: function() {
},
events: {
'submit' : 'submit'
},
submit: function(e) {
e.preventDefault();
var taskNavn = $(e.currentTarget).find('.navnClass').val(),
uriNum = $(e.currentTarget).find('.uriClass').val();
if ( ! $.trim(taskNavn)) {
var test = prompt('opgaven skal have et navn', '');
if ( ! $.trim(test)) return false;
taskNavn = test;
}
if( uriNum.indexOf( "http://" ) == -1 ) {
addedValue = 'http://',
uriNum = addedValue + uriNum;
}
$(e.currentTarget).find('input[type=text]').val('').focus();
//var task = new App.Models.Task({ name: taskNavn, uri: uriNum });
this.collection.add({ name: taskNavn, uri: uriNum });
}
});
// new tasks collection
var tasks = new App.Collections.Tasks([
{
name: 'Foo',
uri: 'www.google.com',
counter: 3
},
{
name: 'Bar',
uri: 'http://google.com',
counter: 2
},
{
name: 'Baz',
uri: 'http://www.google.com',
counter: 1
}
]);
// tasks.comparator = function(task) {
// return task.get("counter");
// };
tasks.sort();
// new collection view (add)
var addTaskView = new App.Views.AddTask({ collection: tasks});
// new collection view
var tasksView = new App.Views.TasksView({ collection: tasks });
$('.tasks').html(tasksView.el);
})();
My HTML: (if someone wanna try to replicate the scenario :)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LinkList</title>
</head>
<body>
<h1>Mine opgaver</h1>
<form action="" id="addTask">
<input class="navnClass" type="text" placeholder="Link name"><input clas s="uriClass" type="text" placeholder="www.url-here.com">
<button class="nyOpgave">Ny opgave</button><br />
</form>
<div class="tasks">
<script type="text/template" id="Tasks">
<span class="linkNavn"><%= name %></span> - <%= uri %> : [<span class="counterClass"><%= counter %></span>] <button class="edit">Edit</button> <button class="delete">Delete</button>
</script>
</div>
<script src="js/underscore.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script src="js/jquery.js"></script>
<script src="js/backbone.js"></script>
<script src="main.js"></script>
</body>
</html>
can anyone please help me figure this one out ?
/Cheers
Marcel
Okay , i have created the application for you , as you have intended it to run.I'm going to try and explain you the entire code , what i have written and why i have written.
First , take a look at the JSfiddle : here
Next , let me explain :
1.This is my model that stores the name of the link , href , the id(not used in my example but its just good practise to assign a unique id to each model) and finally the number of clicks to a link(model).
var myModel = Backbone.Model.extend({
defaults:{
'id' : 0,
'name' : null,
'link' : '#',
'clicks' : 0
}
});
2.This the collection , that stores all my models , i have added a comparator function so that when ever you add a model to a collection , it will sort the collection.
Note : i have added a - sign to sort the collection in descending order of clicks (link with maximum click to appear first)
var myCollection = Backbone.Collection.extend({
model: myModel,
comparator: function(item) {
return -item.get('clicks');
}
});
3.Now this is my main view , what do i mean main view ? This view does the main rendering of the list , that you want to show.Pretty self explanatory code here.One thing , the this.coll.bind('add change',this.render,this) , i have added a 'change' because whenever any of the models in this collection change , we want to re-render the entire list , this happens when i change the count of any link , on clicking it , i want to re-render the entire list.
var myView = Backbone.View.extend({
el: $("#someElement"),
tagName : 'ul',
initialize: function() {
this.coll = new myCollection();
this.coll.bind('add change',this.render,this);
},
events: {
"click #add": "add"
},
add: function(e){
e.preventDefault();
var mod = new myModel();
var name = $('#name').val();
var link = $('#link').val();
mod.set({'id':mod.cid, 'name':name,'link':link});
this.coll.add(mod);
},
render : function(){
$('#list').empty();
this.coll.sort();
this.coll.forEach(function(model){
var listItem = new printView({ model: model});
$('#list').append(listItem.render().el);
});
}
});
4.This is my sub-view , why do i ever make a second view , why isnt 1 view sufficient ?
Well this consider a scenario, with every link you have a delete button (for instance) when i click the delete button (and i have just 1 view) how do i identify which model to destroy(remove from collection ? ) , 1 possible way would be to associate a cid with each model and then on click i can do a this.coll.getByCid() , but this isnt such a good way to do it , IMHO , so i created a separate view for each model.This View renders each model and returns nothing more.
var printView = Backbone.View.extend({
tagName: 'li',
initialize : function(options) {
_.bindAll(this, "render");
},
events:{
"click a": "count"
},
render:function(){
var linkName = this.model.get("name");
var link= this.model.get("link");
var clicks = this.model.get("clicks");
this.$el.append("<a class='link' href='"+link+"'>"+linkName+"</a> ("+clicks+")");
return this;
},
count:function(e){
e.preventDefault();
e.stopPropagation();
var clicks = this.model.get("clicks");
clicks++;
this.model.set({'clicks':clicks});
}
});
5.Initializing my (main) myView
new myView();
Note: I do believe that this application/code can be written in much better way , with several improvements but with my calibre and with the fact that it works ( :p ) i think it can help you.
The collection comparator is only executed when new models are added to the collection: it doesn't update the collection order when properties change. In order to achieve this, you need to call collection.sort():
App.Collections.Tasks = Backbone.Collection.extend({
model: App.Models.Task,
initialize: function() {
this.on('change:counter', this.sort);
},
comparator: function(task) {
return task.get('counter');
}
});
In the list view you can listen to the collection's sort event, and re-render your view:
App.Views.TasksView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('add', this.addOne, this);
this.collection.on('sort', this.render, this);
this.render();
},
render: function() {
//if there are existing child views, remove them
if(this.taskViews) {
_.each(this.taskViews, function(view) {
view.remove();
});
}
this.taskViews = [];
this.collection.each(this.addOne, this);
return this;
},
addOne: function(task) {
var taskView = new App.Views.TaskView({ model: task });
this.$el.append(taskView.render().el);
//keep track of child views
this.taskViews.push(taskView);
}
});